Classloader由弱引用持有?

adi*_*tsu 11 java garbage-collection memory-leaks classloader

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

如果我排除弱参考,列表是空的!这怎么可能,因为只有弱引用持有的对象应该收集垃圾?(我在jconsole中多次执行GC)

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

  • java.lang.reflect.Proxy.loaderToCache
  • java.lang.reflect.Proxy.proxyClasses
  • java.io.ObjectStreamClass中的$ Caches.localDescs
  • java.io.ObjectStreamClass中的$ Caches.reflectors
  • java.lang.ref.Finalizer.unfinalized

我找不到任何理由为什么这些引用应该防止垃圾收集类加载器.这是一个gc bug吗?特殊无证案件?jmap/jhat bug?或者是什么?

最奇怪的是......在闲置和闲逛之后大约40分钟,没有改变任何东西,它最终决定卸载类并收集类加载器.

注意:

如果您对延迟收集类加载器或弱引用提出声明,请说明发生的情况,理想情况是:

  • 提供指向支持您的声明的权威文章的链接
  • 提供演示行为的示例程序

如果您认为该行为是依赖于实现的,那么请关注oracle或icedtea jvm版本6或7中发生的事情(选择其中任何一个并具体说明).

我真的想深究这一点.我实际上已经花了一些力气来重现测试程序中的问题,但我失败了 - 除非有强烈的引用,否则每次都会立即在System.gc()上收集类加载器.

adi*_*tsu 6

看起来某处涉及软引用。这是我能找到的延迟收集(约 40 分钟)的唯一解释。我最初认为软引用会一直保留到内存耗尽,但我发现事实并非如此。

来自此页面:“软可访问的对象将在上次被引用后的一段时间内保持活动状态。默认值是堆中每空闲兆字节的生命周期一秒。可以使用 -XX:SoftRefLRUPolicyMSPerMB 调整此值旗帜”

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

我认为软引用来自 ObjectStreamClass。问题是为什么 jhat 没有在 rootset 引用中显示它。是因为它不强也不弱吗?还是因为它已经找到了来自相同静态字段的弱引用?还是其他什么原因?无论哪种方式,我认为这需要在 jhat 中改进。