Java 弱引用持有的类加载器?

Java 弱引用持有的类加载器?,java,memory-leaks,garbage-collection,classloader,Java,Memory Leaks,Garbage Collection,Classloader,我一直在与一些内存泄漏作斗争,目前我对这个问题感到困惑。有一个web应用程序类加载器应该被垃圾收集,但它不是(即使在我修复了几个漏洞之后)。我用jmap转储了堆,用jhat浏览了堆,找到了类加载器并检查了根集引用 如果排除弱引用,则列表为空!既然只由弱引用持有的对象应该被垃圾回收,这怎么可能呢?(我在jconsole中多次执行GC) 如果我包括弱引用,我会得到一个引用列表,所有引用都来自以下字段之一: java.lang.reflect.Proxy.loaderToCache java.lan

我一直在与一些内存泄漏作斗争,目前我对这个问题感到困惑。有一个web应用程序类加载器应该被垃圾收集,但它不是(即使在我修复了几个漏洞之后)。我用jmap转储了堆,用jhat浏览了堆,找到了类加载器并检查了根集引用

如果排除弱引用,则列表为空!既然只由弱引用持有的对象应该被垃圾回收,这怎么可能呢?(我在jconsole中多次执行GC)

如果我包括弱引用,我会得到一个引用列表,所有引用都来自以下字段之一:

  • java.lang.reflect.Proxy.loaderToCache
  • java.lang.reflect.Proxy.ProxyClass
  • java.io.ObjectStreamClass$Caches.localDescs
  • java.io.ObjectStreamClass$Caches.reflector
  • java.lang.ref.Finalizer.unfinalized
我找不到任何理由说明为什么这些引用会阻止垃圾收集类加载器。这是一个gc错误吗?特殊无证案件?jmap/jhat bug?还是什么

最奇怪的是。。。在闲置和时不时地执行gc操作大约40分钟后,没有任何更改,它最终决定卸载类并收集类加载器

注意:

如果您对类加载器的延迟收集或弱引用提出索赔,请指定发生的情况,理想情况下:

  • 提供支持您的声明的权威文章的链接
  • 提供一个示例程序来演示该行为
如果您认为行为依赖于实现,那么请关注oracle或icedtea jvm版本6或7中发生的情况(选择其中任何一个并具体说明)


我真的很想弄清这件事的真相。实际上,我花了一些精力在测试程序中重现这个问题,但我失败了——每次都会在System.gc()上立即收集类加载器,除非有对它的强引用。

类驻留在特殊内存空间中-永久生成。卸载类加载器。GC应该选择将perm空间包含到集合的范围中。不同的GC算法有一些不同的行为,但一般来说,GC会尽量避免perm空间收集


根据我的经验,即使类加载器不可访问,JVM在尝试收集PERM空间之前也可能会出现OutOfMemoryError

似乎在某个地方涉及到了软引用。这是我能找到的关于延迟收集(大约40分钟)的唯一解释。我最初以为软引用会一直保留到内存耗尽,但我发现事实并非如此

From:“软访问对象在上次引用后的一段时间内将保持活动状态。默认值为堆中每空闲兆字节一秒的生存期。可以使用-XX:SoftRefLRUPolicyMSPerMB标志调整此值”

因此,我将该标志调整为1,并在几秒钟内收集了类加载器


我认为软引用来自ObjectStreamClass。问题是为什么jhat没有在根集引用中显示它。是因为它既不强也不弱吗?还是因为它已经从相同的静态字段中找到了弱引用?还是其他原因?不管怎样,我认为jhat中的这一点需要改进。

那么你的问题在哪里呢?你试过Java 7 update 40吗?如果它是一个bug,它可能已经被修复了。@isnot2bad做了所有你认为正常的事情@PeterLawrey目前正在使用icedtea 6.1.12.6,我将尝试第7版later@PeterLawrey我刚刚试过使用icedtea 7.2.4.3,同样的情况也发生了,唯一的区别是com.sun.beans.TypeResolver.CACHE中还有一个弱引用。我还没有等待40多分钟,看看它是否最终收集了类加载器。请参阅我添加到问题中的注释。我怀疑
jhat
未命中它的原因是
ObjectStreamClass.class
无法通过
classloader.class
访问,因为它位于引导类路径中。换句话说,JRE类中静态字段持有的任何引用都将丢失。