dead class 加载程序不是从 permgen 收集的垃圾
dead class loaders not garbage collected from permgen
我从 "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
....
现在 permGen 中有超过 6000 个这些死的 TransletClassLoader class 加载器,并且数量一直在增长,直到我收到此错误:
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)
为什么这些死掉的 class 加载程序在 CMSClassUnloadingEnabled 标志打开的情况下没有被清理?我该如何解决这个问题?
您 class 加载程序泄漏。典型的模式是这样的。
- 您创建新的 classloader
- 您在新的 classloader
中加载 classes
- 您从 classes 之一创建实例。
- 您将实例放入一个数据结构中(例如),使其永久可达。
- 您放弃了对 classloader 的引用。
问题是只要您创建的实例可以访问,我们就需要 1) 实例的 classes 方法的代码 2) Class
对象(或信息做到这一点)以防有人在实例上调用 getClass()
。
这意味着(实际上)class 必须可达。
但是 Class
有一个 getClassloader
方法,所以 classloader 对象也必须是可访问的。
典型的 classloader 对象具有对其加载的所有 classes 的内部引用,因此它们也必须都可以访问。
简而言之,确保您没有保留对使用死 classloader 加载的 classes 实例的引用。它们将阻止 classloader 被垃圾收集。
作为 Stephens anser 的后续,您可能需要查看 this blog series of mine 以了解如何追踪类加载器泄漏。
或者您可能只想跳过并在您的申请中添加 my Classloader Leak Prevention library。
祝你好运!
P.S。如果您调试它并发现 Xalan 中存在泄漏,请告诉我,以便我更新 the list of known offenders.
我从 "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
....
现在 permGen 中有超过 6000 个这些死的 TransletClassLoader class 加载器,并且数量一直在增长,直到我收到此错误:
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)
为什么这些死掉的 class 加载程序在 CMSClassUnloadingEnabled 标志打开的情况下没有被清理?我该如何解决这个问题?
您 class 加载程序泄漏。典型的模式是这样的。
- 您创建新的 classloader
- 您在新的 classloader 中加载 classes
- 您从 classes 之一创建实例。
- 您将实例放入一个数据结构中(例如),使其永久可达。
- 您放弃了对 classloader 的引用。
问题是只要您创建的实例可以访问,我们就需要 1) 实例的 classes 方法的代码 2) Class
对象(或信息做到这一点)以防有人在实例上调用 getClass()
。
这意味着(实际上)class 必须可达。
但是 Class
有一个 getClassloader
方法,所以 classloader 对象也必须是可访问的。
典型的 classloader 对象具有对其加载的所有 classes 的内部引用,因此它们也必须都可以访问。
简而言之,确保您没有保留对使用死 classloader 加载的 classes 实例的引用。它们将阻止 classloader 被垃圾收集。
作为 Stephens anser 的后续,您可能需要查看 this blog series of mine 以了解如何追踪类加载器泄漏。 或者您可能只想跳过并在您的申请中添加 my Classloader Leak Prevention library。
祝你好运!
P.S。如果您调试它并发现 Xalan 中存在泄漏,请告诉我,以便我更新 the list of known offenders.