何时以及如何将java classloader标记为垃圾收集?
我们正在创build多个子类加载器,将多个子应用程序加载到Java应用程序“容器”中,进行热部署的原型devise。 当一个特定类加载器的类path发生了变化(例如,jar被添加,删除,更新)时,旧的类加载器被抛弃(未引用),并为jar的新类path创build一个新的类加载器。
更新类path后,触发热部署,我们采取了堆转储。 堆转储(使用内存分析器)表明旧的类加载器没有被垃圾回收。 父类加载器中的某些类正在caching旧的类加载器。 下面的东西被调用来清除这些caching:
java.lang.ResourceBundle.clearCache(classLoader); org.apache.commons.logging.LogFactory.release(classLoader); java.beans.Introspector.flushCaches();
即使在清除了上述caching之后,旧的加载器仍然没有被垃圾收集。 其余的类加载器引用如下:
- 由类加载器加载的类
- java.lang.Package由类加载器本身创build
- java.lang.ProtectionDomain由类加载器本身创build
以上所有都是类加载器中的循环引用,它应该触发一个垃圾回收。 我不知道为什么不是。 有人知道为什么旧的类加载器仍然不被垃圾收集,即使是循环引用?
我总是听说Classloader
卸载是有问题的。 当没有引用对象实例时,它们在理论上是垃圾收集的,并且类卸载不是必需的,但是在实践中似乎更成问题。 微妙的引用可能会泄漏并阻止Classloader
被回收。 在应用程序服务器中,经过大量的重新部署周期,我有时会遇到OutOfMemoryError: PermGen space
。
所有这一切说,我想有一个讨厌的参考,以防止它被收集 – 也许内存分析器没有正确地遵循链接。 似乎所有这些都可能发生,正如这些文章所描述的那样:
- 类加载器泄漏:可怕的PermGen空间exception
- 如何解决可怕的PermGen空间exception
另外,我不知道你在做什么,但如果你可以等待JDK 7,你可以看看AnonymousClassLoader
。 将会介绍它们以更好地支持dynamic语言,正如本文中所解释的:
- InvokeDynamic的第一味道
我希望这会帮助你。