已过时的类加载器在PermGen区域中没有被垃圾回收。

3
我从 "jmap -permstat" 命令中看到以下信息:
0x000000077736cce0      12      173472  0x00000007723425d0      dead    com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl$TransletClassLoader@0x00000007c83bea70
0x0000000777168a20      12      172264  0x00000007723425d0      dead    com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl$TransletClassLoader@0x00000007c83bea70
0x0000000780b3c810      12      172264  0x00000007723425d0      dead    com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl$TransletClassLoader@0x00000007c83bea70
0x0000000776ca6170      12      172264  0x00000007723425d0      dead    com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl$TransletClassLoader@0x00000007c83bea70
0x00000007772b28a8      12      172264  0x00000007723425d0      dead    com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl$TransletClassLoader@0x00000007c83bea70
....

现在永久代中有超过6000个已经死亡的TransletClassLoader类加载器,并且这个数字会不断增长,直到我遇到以下错误:

java.lang.OutOfMemoryError: PermGen space

我设置了以下JVM标志:

-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSClassUnloadingEnabled

java version "1.6.0_33"
Java(TM) SE Runtime Environment (build 1.6.0_33-b04)
Java HotSpot(TM) 64-Bit Server VM (build 20.8-b03, mixed mode)

为什么启用CMSClassUnloadingEnabled标志后,这些已死的类加载器没有被清理掉?我该如何解决这个问题?
2个回答

4
您有一个类加载器泄漏。典型的模式如下:
- 您创建新的类加载器 - 您在新的类加载器中加载类 - 您从其中一个类创建实例。 - 您将实例放入数据结构(例如),使其永久可达。 - 您放弃对类加载器的引用。
问题在于,只要您创建的实例是可达的,我们就需要1)实例类方法的代码2)Class对象(或制作它的信息),以防有人在实例上调用getClass()
这意味着该类(实际上)必须是可达的。
但是Class有一个getClassloader方法,因此类加载器对象也必须是可达的。
而且典型的类加载器对象具有对其加载的所有类的内部引用,因此它们也必须是可达的。
简而言之,请确保您不会保留对使用已死类加载器加载的类实例的引用。它们将阻止类加载器被垃圾回收。

请注意,“对ClassB的引用”可以简单地是ClassA具有类型为ClassB的空引用变量,或包含具有ClassB参数的方法调用。甚至不需要ClassA的实例。这意味着您必须始终使用按名称查找方案来引用ClassB,以从其类加载器外部的某个位置引用它,并且必须始终使用接口或超类来引用其实例。 - Hot Licks
什么会导致Discard Classloader? - Kalpak Pingle
当一个ClassLoader变得不可达时,它才能被垃圾回收。 - Stephen C

1
作为对 Stephens 答案的跟进,您可能想查看我的博客系列了解如何追踪类加载器泄漏。或者您可以直接跳过并将我的类加载器泄漏预防库添加到您的应用程序中。
祝好运!
P.S. 如果您调试并发现Xalan中存在泄漏,请告诉我,以便我可以更新已知罪犯列表

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接