Java中是什么触发了完整的垃圾回收?

24

我想知道在Java中触发完整垃圾回收的确切情况。

明显的情况包括:

  • 老年代用尽
  • 永久代用尽
  • 调用System.gc()

其他什么情况会导致完整的垃圾回收呢?特别是:

  • 幸存者区没有足够的空闲空间从伊甸园复制对象。
  • 新生代的小型集合不能应对新对象的分配速率(不知道如何处理)。

我正在运行Sun Java 1.6,使用并发标记-清除和ParNew作为新生代。


1
正如Chin Boon所建议的那样,这些“显而易见”的方法不一定会导致完整的GC,这完全取决于活动垃圾收集器算法的工作方式。特别是,我理解很多垃圾收集器或多或少地忽略了System.gc()。(不要忘记,甚至有可能一个GC算法没有“完整收集”的概念 - 这听起来可能有些牵强,但我在我们的应用程序上还没有看到G1收集器这样做。) - Andrzej Doyle
当JVM使用G1运行时,当它用尽堆空间时,您认为会发生什么?继续分配吗?它必须停止一切直到它释放内存。有一个开关可以显式关闭System.gc()提示,但是我还没有看到CMS或G1默认忽略它。 - Paweł Krupiński
我猜这取决于你如何定义“完整集合” - 我不认为它是JLS或VM规范上的一流术语。其含义将因您运行的特定GC算法而异,甚至对于给定的GC实现可能没有意义。我试图指出的是唯一可能的一般答案是“这取决于情况”,所有其他细节都推迟到特定垃圾收集器的内部处理。 - Andrzej Doyle
1
我认为完整收集有一个共同点。完整收集被定义为在整个持续时间内线程都停止的收集。即使CMS有短暂的暂停,当进行完整收集时,整个JVM也会在整个收集期间暂停。使用CMS进行完整收集实际上是两个CMS运行 - 一个用于旧代,一个用于永久代。我想G1也是完全相同的。 - Paweł Krupiński
1
本文提供了G1中完整收集的示例(当增量收集失败时):http://blog.ragozin.info/2011/12/garbage-collection-in-hotspot-jvm.html。如果Hotspot GC日志识别到“Full GC”这个术语,我认为它是相当正式的。 - Paweł Krupiński
是的,说得好,G1有一个停止世界的收集过程。然而,这并不是垃圾回收的必要条件,例如,一个收集器可以将堆分成两部分,在后台收集一个完整的堆,同时使用另一个堆,而不需要停止整个系统。例如,Zing JVM的GC根据你的定义不进行任何完整的收集。我的观点是,关于垃圾回收,你能够做出的假设非常少 - 除了收集器在发生内存溢出之前会最终回收一个弱可达对象之外,它几乎可以自由地进行操作。 - Andrzej Doyle
2个回答

4
我观察到一种情况会在64位Ubuntu上使用Concurrent Mark-Sweep的Java Hotspot VM 1.6中触发full GC: 如果-XX:PermSize值不等于-XX:MaxPermSize(例如较小),则在java需要扩展PermGen时会偶尔发生Full GC(即使它不需要分配比MaxPermSize更多的内存)。因此,将-XX:PermSize和-XX:MaxPermSize设置为相同似乎是个好主意。

这怎么成为一个被接受的答案了呢?PermGenSpace对full gc没有任何影响。你是指xmx和xms参数吗? - Amareswar
@Amareswar Oracle表示:“永久代被包含在完整的垃圾回收中。” - Gamby

2
这在很大程度上取决于您使用的JVM选项和JVM版本。因此,我建议您阅读John和Hunt所著的《Java性能》一书。

1
至少针对JVM实现和垃圾回收器,必须有一些通用的规则。 - Paweł Krupiński

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