原文

Jack Shirazi 告诉你 Oracle Java 7 update 4 及更高版本可以使用哪些GC和GC的组合, 包括Java 8 和Java9

发布日期: June 2012, 更新日期: September 2015, 作者 Jack Shirazi

注意, 这已经更新到 Java 8 和 Java 9

随着G1终于在 1.7.0_04(Java 7 update 4) 版本中正式得到官方支持 - 即不再是实验性GC了, 值得评估我们现在在 Sun JVM 中的GC可用性. 以下所有详细信息都与来自 1.7.0_04 的 Sun JVM 相关.

现在有七种主要的GC算法(其中一种 PS Scavenge) 有两种模式, 这两种模式足够不同, 我称它们为两种不同的算法.(即, 有没有自适应GC), 另一种( concurrent collector, 并发收集器)有大量的选项, 使得其中一种GC至少有6种算法. 列出GC是非常有用的, 所以这就是我要做的.

首先, 我将描述实际不同的主GC. 有七个(我将G1列为一个)

Young generation collectors

Copy (通过 -XX:+UseSerialGC 开启)

serial copy collector (串行复制收集器)使用一条线程将幸存对象从 eden 复制到 survivorsurvivor 空间之间, 直到它们已经存在足够长的时间, 然后将它们复制到 old generation

PS Scavenge (通过 -XX:+UseParallelGC 开启)

parallel scavenge collector(并行扫描收集器), 与 Copy collector 类似, 但并行使用多条线程, 并具有一些如何收集 old generation 的信息(基本上是为了与 serial 与 PS old generation collector 一起工作而编写的)

ParNew (通过 -XX:+UseParNewGC 开启)

parallel copy collector(并行复制收集器), 类似 copy collector, 但并行使用多条线程, 并具有内部 callback: 允许与 old generation collector 对其收集的对象进行操作(实际上是为了与 concurrent collector 一起工作而编写的)

G1 Young Generation ( 通过 -XX:+UseG1GC 开启)

G1 收集器, 使用 Garbage First 算法, 将堆分成许多较小的空间, 但这些仍然分为 young generation 中的 eden, survivor 空间.

Old generation collectors

MarkSweepCompact ( 通过 -XX:+UseSerialGC 开启)

serial mark-sweep collector , 使用一个(一条线程) serial full mark-sweep garbage collection 算法, 并且可选压缩.

PS MarkSweep ( 通过 -XX:+UseParallelOldGC 开启)

parallel scavenge mark-sweep collector, 即 MarkSweepCompact 的并行版本(即使用多线程)

ConcurrentMarkSweep ( 通过 -XX:+UseConcMarkSweepGC 开启)

concurrent collector(并发收集器), 一种GC算法, 它试图在后台执行大部分的GC工作, 而不会停止应用程序线程的工作线程(仍有一些阶段, 它必须停止应用程序线程, 但这些阶段试图保留最小). 请注意, 如果 concurrent collector 无法跟上垃圾的话, 它将故障转移到下次GC的 serial MarkSweepCompact collector.

G1 Mixed Generation ( 通过 -XX:+UseG1GC 开启)

G1 收集器, 使用 Garbage First 算法, 将许多堆分成更小的空间.

除了 ConcurrentMarkSweep 之外, 所有的GC算法都是 stop-the-world 的, 即它们在工作时会停止所有的应用程序线程-停止被称为 暂停时间 (pause time). ConcurrentMarkSweep 试图在后台完成大部分工作, 并尽量缩短暂停时间, 但它也有一个 stop-the-world 阶段, 并且可能会陷入 full stop-the-worldMarkSweepCompact(G1 收集器有一个 concurrent 阶段, 但目前大多是 stop-the-world)

GC 的组合

这是一组可用的GC, 但它们在两上不同的堆空间中运行, 并且它是我们实际结束特定JVM设置的组合, 因此我还会列出可能的组合. 它不会爆炸成十几种组合, 因为并非所有这些GC都能相互协作. G1 实际上是 antisocial collector , 不喜欢与其他人一起工作; serial collector 是一个 last man picked 收集器(译注: 即最后一个选择的); PS collector 喜欢与其他协作; ParNewconcurrent 喜欢一起工作. 从Java 9来说, 它几乎就是这样(除了能够关闭自适应大小调整策略之外), 在此之前, 它并不那么简单, 所以这里列出了我认为是GC的主要选项收集算法选项. 对于那些喜欢一些琐事的人来说, 我们实际上已经丢失了一段GC算法. train (增量) GC 可以在各种JVM如 -Xincgc-XX:+UseTrainGC 这些标志不再适用, 前一个选项只是静默地转换为使用 ParNewconcurrent, 而后一个选项将导致此JVM 启动错误, 并且在Java 9中, 我们也失去了 concurrent collector 的增量算法.

可以工作的可用的GC算法组合的完整列表如下:

组合选项 实际的收集器组合
XX:+UseSerialGC young Copy and old MarkSweepCompact
-XX:+UseG1GC young G1 Young and old G1 Mixed
-XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy young PS Scavenge old PS MarkSweep with adaptive sizing
-XX:+UseParNewGC (Java 8 中废弃, Java9中被移除, 但下面一行并不废弃) young ParNew old MarkSweepCompact
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC young ParNew old ConcurrentMarkSweep**
-XX:+UseConcMarkSweepGC -XX:-UseParNewGC (Java 8 中废弃, Java 9 中被移除) young Copy old ConcurrentMarkSweep**

如果添加另一个未列出的GC算法, 则此处列出的所有组合都将无法启动JVM, 但 -XX:+UseParNewGC 只能与 `-XX:+UseConcMarkSweepGC** 组合使用.

有许多可用于 -XX:+UseConcMarkSweepGC 的选项, 它可以改变算法, 例如: -XX:+/-CMSIncrementalMode : (java 8 中废弃, Java9中被移除): 使用或禁用增量式 concurrent GC 算法 -XX:+/-CMSConcurrentMTEnabled : 使用或禁用并行(多线程)concurrent GC 算法 -XX:+/-UseCMSCompactAtFullCollection : 地 full GC 发生时使用或禁用压缩

其他等同是以上之一的选项:

它们自己在命令行选项使用时 等同于上表之一
-XX:+UseParallelGC -XX:+UseParallelGC -XX:+UseParallelOldGC
-XX:+UseParallelOldGC -XX:+UseParallelGC -XX:+UseParallelOldGC
-Xincgc (java 8 中废弃, java 9 中被移除) -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+UseConcMarkSweepGC
在大部分 Windows 中没有选项时 -XX:+UseG1GC (java 9 的话), -XX:+UseSerialGC (<java 9 参考
在大部分 Unix 中没有选项时 -XX:+UseG1GC (java 9的话), (<java 9) -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy , 参考
-XX:+AggressiveHeap -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy 与一堆其他选项有关的大小内存和线程, 以及它们如何与OS交互

联系作者