Java垃圾回收的“实际”时间比“用户”+“系统”的时间长得多。

6
这就是启用详细垃圾回收的完整gc的样子 -
13463.547: [Full GC [PSYoungGen: 323053K->0K(325952K)]
           [PSOldGen: 653170K->331738K(655360K)] 976224K->331738K(981312K)
           [PSPermGen: 238715K->238715K(264448K)], 385.4631490 secs]
           [Times: user=2.19 sys=1.35, real=385.50 secs]

实时时间为什么比用户+系统时间长这么多?

我的第一个想法是垃圾收集器正在等待某个资源,但这个资源似乎不是IO或CPU,因为当gc发生时,“top”输出并没有显示任何cpu或内存问题。


如果它不在等待IO,也不是CPU密集型的话,那么我能想到的唯一可能就是在等待信号量/互斥锁,或者是非常非常慢的内存访问。 - Jonathan
你的应用程序中使用JNI吗?你的堆大小是多少,你有多少物理内存? - Ron
Xmx = 960 Mb,RAM = 4GB,我们使用JNI但不是太频繁,JNI如何影响垃圾回收? - Artiom Gourevitch
2个回答

7
为了进行完整的收集,您需要停止所有线程。(这也是称之为“停止全球收集”的原因之一)
停止所有线程可能需要很长时间,特别是如果您有成千上万个线程。每个线程都必须到达一个“安全点”才能停止它。
这种行为通常意味着您有太多线程。您还可以考虑使用ConcurrenntMarkSweep收集器或新的G1收集器,它不需要经常停止应用程序。

2
这可能是一个线索。长时间的GC发生在启用了Yourkit代理的QA环境中。它可能会阻止线程到达安全点,因为我们以前就遇到过与其性能相关的问题。 - Artiom Gourevitch

1

尝试阅读这篇文章(更多白皮书链接):Java 1.5 GC 内部
我猜大多数内容对于 Java 的 1.6 VM 仍然有效,并且它可以很好地解释 GC 的工作原理。
此外,还要阅读这篇文章:Tuning JVM's 1.6 Heap space
(还有另一个带有说明性基准的白皮书链接,但我找不到它 :( :/
我会尝试看看是否会在某个地方出现,但我猜它位于 Oracle 的网站上)

总的来说,不要过于神经质。根据一些合理的理由尝试并实验不同的选项,看看它们的效果如何。除非您获得了超过 10% 的性能提升并且您的应用程序至关重要,否则请不要涉及太多细节。
原因很简单:只需重写几行代码就可能极大地改变您的 GC 行为。
花点时间,玩得开心!:)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接