【问题标题】:Leaving Classloader open after first use首次使用后保持 Classloader 打开
【发布时间】:2012-12-06 08:40:35
【问题描述】:

我正在创建一个 URLClassloader 来加载一些 jar。每个 jar 都从不同的类加载器正确加载,并且每个 jar 都包含一个带有方法 run() 的类。现在这个 run() 的主体可以在其中创建一个匿名内部类。但是,因为我在 try-with-resources 块中创建了我的 URLClassloader,所以它会自动关闭,并且在运行时当它尝试加载匿名内部类时,它会抛出 NoClassDefFoundError,因为类加载器已经关闭。

现在我的问题是,这些情况的正常做法是什么? 是否可以让类加载器保持打开状态,以便以后需要加载其他内容时,它可以吗?有没有办法重新打开关闭的类加载器?
如果我让类加载器保持打开状态,编译器会向我发出有关潜在资源泄漏的警告所以我觉得这就像你不应该让它们无限期打开的流。但是由于类加载器的性质,如果不是同一个加载匿名类的类加载器,就不能在外部类中使用

这是创建类加载器的代码

public Player(File codePath) throws PlayerException {

   try (URLClassLoader loader = new URLClassLoader(new URL[] { codePath.toURI().toURL() })) {

   //load class from Jar where run() method creates anonymous class that comes in the jar too


   } catch (ClassCastException | IOException | ClassNotFoundException | InstantiationException
| IllegalAccessException | IllegalArgumentException | InvocationTargetException
| SecurityException exc) {
throw new PlayerException("Error loading player's code", exc);

}

【问题讨论】:

  • 请注意,“关闭”类加载器与删除它不同。只要任何用它加载的类仍然在任何地方引用,加载器就仍然存在。 “关闭”它只是回收用于访问类路径的资源。如果您创建了很多类加载器,那么这些资源可以加起来(特别是进程打开文件句柄限制)。如果只有几个,那没什么大不了的。

标签: java classloader


【解决方案1】:

类加载器的生命周期至少应该是加载它的类实例的生命周期。只要他们和他们的类不符合垃圾回收的条件,他们的类加载器也不是。如果他们需要加载额外的代码或资源,您需要打开类加载器。

因此,当您完成播放器时,您应该关闭类加载器。

【讨论】:

  • 你对离开的成本有什么想法吗,比如基本上为整个游戏开放了 10 个类加载器?现在我确实会在玩家死亡时关闭它们,但那会在一段时间后发生。我想知道这是否是我应该担心的事情
  • 好吧,在玩家被垃圾回收之前,类加载器本身不会被垃圾回收。所以我们可以忽略这个成本。唯一的额外成本是打开的文件描述符。我不知道每个播放器有多少个 JAR,但如果它只有一个,那么每个播放器只有一个文件描述符。
  • 虽然类加载器的生命周期应该(实际上将是)至少是已加载类的生命周期,但这并不意味着用于加载类的路径必须保持打开状态。通常,当知道不再通过它加载类时,加载器应该“关闭”。
  • 是的,但很难知道这一点。由于类加载是动态的,并且对象仍在使用中,因此您无法确定将来是否需要加载额外的类或资源。
【解决方案2】:

您可以使用工厂模式(或类似的东西),而不是为每个玩家创建一个新的类加载器:

URLClassLoader loader = PlayerClassLoaderFactory.getInstance().getClassLoader(codePath.toURI())

工厂维护对类加载器的引用(因此类不是孤立的)。然后,如果需要关闭类加载器,您就可以“关闭”工厂。

【讨论】:

  • 这是一个很好的建议,但它并没有回答我的问题,因为类加载器是应该在加载播放器结束时关闭还是在整个游戏中保持打开的问题仍然需要回答.我实际上所做的只是将局部变量设为类成员,因为类加载器是播放器的属性,但我会考虑将其设为工厂
  • 如果在初始化过程中你最终加载了所有你需要的类到 permgen,那么你可以关闭它,因为这些类在关闭后仍然可以访问。但是,如果不是这种情况,则应将其保持打开状态以防加载其他类(例如,由于用户操作)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-31
  • 1970-01-01
相关资源
最近更新 更多