当一个类加载器被释放时,什么时候会在单例上调用?

时间:2012-02-28 21:11:46

标签: java java-ee permgen finalize dynamic-class-loaders

通过“已发布”,我的意思是没有对类加载器的引用。

我们遇到了一个问题,即频繁重新部署的Java EE应用程序会占用permgen空间。分析表明,Java EE应用程序中的单例已经传递了对应用程序之外的应用程序类加载器对象的引用(违反Java EE规则),并且在取消部署应用程序时不会清除它们。

假设单例或类对象没有其他引用,单个类的finalize()会在其类的类加载器被释放时被调用吗?我想清除流氓 - 绑定引用那里。或者我在catch-22中,在类加载器本身可以被垃圾收集之前不会调用finalize - 因此永远不会因为流氓外部引用而被调用?

这里的主要问题可能是:

在这种情况下,类对象是否还不能被垃圾收集?这可能取决于类加载器行为的规范,或者可能依赖于实现。

参考文献(另一种!;-))将不胜感激,但不是必需的。

2 个答案:

答案 0 :(得分:4)

具有静态引用的类只有在类加载器符合GCing条件并且没有其他引用的情况下才有资格进行垃圾回收。

  

当且仅当垃圾回收器可以回收它的定义类加载器时,才可以卸载类或接口。

http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.7

此外,每个类都有对其类加载器的引用。因此,只要引用了由类加载的类或来自不可收集对象的类的对象,类加载器就不符合GCing的条件。

在对象符合垃圾收集条件并且在实际GC发生之前,终结器会运行一段时间。

在终结器中使用防止GCing的免费传入引用的方法不起作用。只要存在此类引用,就不会调用终结器,因为它们会阻止对象符合垃圾回收的条件。例如,您无法从内部破坏此参考链:

singleton instance <--- singleton class <--- class loader <--
<-- any class loaded by that class loader  <-- any object of such a class
<-- object loaded by another classloader referencing such an object or class

答案 1 :(得分:0)

终结者的行为不会改变类加载器或使用perm gen,尽管它确实会使性能问题变得更糟。在终结器运行之后才能收集对象。因此(通过假设非并发,并忽略弱/软/幻像来简化)有一个GC运行,它确定没有对象图的活动引用,包括类加载器。终结者将添加到终结队列中,然后执行。然后在GC的一些后续传递之后,可以恢复存储器。这需要一个完整的GC,包括perm gen空间,这通常很少,可以被禁用。

无论如何,不​​要使用(有状态的)单身人士。