繁体   English   中英

为什么 JVM 需要这么长时间才能 GC 我无法访问的 object?

[英]Why does it take the JVM so long to GC my unreachable object?

我一直在处理我们应用程序中的类加载器泄漏问题,最后到了所有对 CL 的引用都消失的地步。 在我的 memory 分析工具(使用 YourKit 和 jmap/jhat)中,我可以强制 GC 有时会立即摆脱我的类加载器,但其他时候(取决于应用程序的使用情况,但这是尽可能具体的)当我强制GC,CL 实例不会 go 离开。 我捕获了一个 memory 快照并查看结果,它说这个 object 存在,但无法访问。

这是古怪的部分......我只是偶然发现了这一点。

我可以强制执行我想要的全部 GC,但实例不会 go 离开。 但是,10-20 分钟后,如果我再做一次完整的 GC,它确实会被收集。

(在此期间,应用程序大部分处于非活动状态(并非完全处于活动状态)。我的“延长”咖啡休息时间是导致这一发现的意外。)

所以我对这里泄漏的担忧已经消失(希望如此),但现在的问题更多是试图解释这种行为。

任何人都知道什么可能导致 sun JVM 决定在 20 分钟内不收集无法访问的类加载器?

孙 JVM 版本详情:

java version "1.6.0_23"
Java(TM) SE Runtime Environment (build 1.6.0_23-b05)
Java HotSpot(TM) 64-Bit Server VM (build 19.0-b09, mixed mode)

我认为 Jeremy Heiler 走在正确的轨道上,这是一个最终确定的问题。 基本上,即使 GC 知道 object 无法访问,在实际收集 object 之前可能仍然需要一段不确定的时间,因为它可能会排队等待最终确定。 终结器线程将不得不完成 object(这可能需要一段时间,这取决于需要终结的其他对象数量以及它们的终结器的外观),然后,在 object 完成之后,您需要另一个GC 重新发现 object 在实际收集之前无法访问。

另外,对于 Sun JVM 上的 ClassLoader,它很可能直接分配到 PermGen。 因此,您不需要一个,而是两个完整的 PermGen 扫描(一个将 object 放入最终队列,然后第二个实际收集它)。 由于 PermGen 扫描很昂贵,我相信 Sun JVM 在默认设置下根本不会这样做,即使有各种 GC 调整,它仍然非常不愿意扫描 PermGen(特别是如果没有很多其他 memory 压力)。

如果不是使用System.gc()强制(嗯,我的意思是鼓励)GC,如果您执行以下操作怎么办:

System.gc();
System.runFinalization();
System.gc();

当然,即使这样也不能保证有效,但它至少做了最少的必要工作来清理需要完成的大型 object。

一个可能的原因是类加载器被软引用持有。 尝试运行

-XX:SoftRefLRUPolicyMSPerMB=1

看看这是否有所作为。 这就是我的情况

可能是因为 JVM 使用分垃圾收集,但最终会进行完整的标记和清除

只是一个猜测:Classloader(及其加载的类)不在通常的堆中,而是在永久代(“PermGen”)中。 This part of the memory will be swiped much less often than everything else, since in normal conditions, class loaders don't go out of scope.

(可能有一些 GC 配置选项会影响这个频率。)我想填充 PermGen 也会在那里触发一个收集,但你通常不想这样做。

事实上,为什么你需要收集你的类加载器?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM