java类加载器何时以及如何标记为垃圾收集?

java类加载器何时以及如何标记为垃圾收集?,java,garbage-collection,classloader,memory-leaks,Java,Garbage Collection,Classloader,Memory Leaks,我们正在创建多个子类加载器,以便将多个子应用程序加载到Java应用程序“容器”中,从而形成热部署的原型。当某个特定类加载器的类路径发生更改(即JAR已被添加、删除、更新)时,旧类加载器将被丢弃(未被引用),并为JAR的新类路径创建一个新类加载器 在更新类路径并触发热部署之后,我们进行了堆转储。堆转储(使用内存分析器)表明旧类加载器没有被垃圾收集。父类加载器中的某些类正在缓存旧类加载器。调用以下内容以清除这些缓存: java.lang.ResourceBundle.clearCache(class

我们正在创建多个子类加载器,以便将多个子应用程序加载到Java应用程序“容器”中,从而形成热部署的原型。当某个特定类加载器的类路径发生更改(即JAR已被添加、删除、更新)时,旧类加载器将被丢弃(未被引用),并为JAR的新类路径创建一个新类加载器

在更新类路径并触发热部署之后,我们进行了堆转储。堆转储(使用内存分析器)表明旧类加载器没有被垃圾收集。父类加载器中的某些类正在缓存旧类加载器。调用以下内容以清除这些缓存:

java.lang.ResourceBundle.clearCache(classLoader);
org.apache.commons.logging.LogFactory.release(classLoader);
java.beans.Introspector.flushCaches();
即使在清除了上述缓存之后,旧的类加载器仍然没有被垃圾收集。对类加载器的其余引用包括以下内容:

  • 类加载器加载的类
  • 包是由类加载器本身创建的
  • 类加载器本身创建的java.lang.ProtectionDomain

以上所有内容都是类加载器中的循环引用,应该触发垃圾收集。我不知道为什么不是。有人知道为什么即使使用循环引用,旧类加载器仍然没有被垃圾收集吗?

我总是听说
类加载器的卸载有问题。当没有对对象实例的引用并且不需要卸载类时,它们被垃圾收集,但在实践中,问题似乎更大。细微的引用可能会泄漏并阻止
类加载器
被回收。在应用服务器中,经过多次重新部署周期后,我有时会遇到一个
OutOfMemoryError:PermGen space

所有这些都意味着,我想在某个地方有一个讨厌的引用阻止了它被收集——也许内存分析器没有正确地遵循链接。这一切似乎都可能发生,如以下文章所述:

另外,我不知道您正在做什么,但是如果您可以等待JDK 7,您可以查看一下
AnonymousClassLoader
。将引入它们以更好地支持动态语言,如本文所述:


我希望它能帮助您。

您使用哪种JVM(确切版本)?您是否使用任何可能影响类加载的JVM选项?您是否使用Sun自己的实现中的任何东西?应用程序是否处理字节码。。。什么环境可能影响类加载?与你的主要问题无关,但是你是否考虑过类似OSGi而不是做支持热部署的自己的框架?@ BFO在我们的测试中,我们使用java 6。没有JVM选项。在最简单的情况下,我们没有使用Sun的impl。没有字节码操作。@stevendick是的,我们考虑过OSGi,但OSGi对于我们的用例来说似乎有些过分。要克服的主要障碍是避免不同子应用程序使用的第三方库发生冲突。子应用程序将使用完全等效的库,但在不同的类装入器中,以避免任何潜在的冲突和复杂性。这听起来好像占用了太多的内存。。。你用过OSGi吗?如果是这样的话,您面临的一些障碍是什么?很清楚,在使用Sun实现时,我的意思是使用套接字通信和序列化,比如RMI/HTTP/SOAP调用等等。这些实现可能使用缓存方法,例如用于序列化问题。这样,您的类(要卸载)被类加载器在您想要清除的类加载器上方和/或旁边引用。这些实现可能使用对类的强引用,以确保序列化不会引起系统/VM IO问题。它使用的唯一第三方库是log4j。没有别的了。其余部分是基本的JDK API。它还使用ResourceBundle类来保存缓存。调用clearCache()后,这些引用确实消失了,但它仍然没有被垃圾收集。但是谢谢你的回答:)哦,顺便说一句,很棒的链接!我只能建议尝试使用有史以来最简单的子应用程序(比如一个类),然后添加越来越多的类和依赖项,看看它在哪一点停止类加载器的GC。但我知道这可能非常耗时。顺便说一句,Frank Kievet也写了一些关于XA事务的有趣文章,如果你感兴趣的话。你是对的。一个令人讨厌的引用正在阻止它被收集。然而,Eclipse内存分析器毕竟正确显示了所有引用。系统的实际架构比我上面描述的要复杂一些,这是为了问题的简洁性而编写的。我将在回答中提供进一步的细节。很高兴听到GC中没有bug,这确实是一个漏洞:)