G1垃圾收集器入门教程(6)——命令行选项和最佳实践

在本节中,我们将学习 G1 收集器的各种命令行选项。

命令行的基本用法

如果要启用 G1 收集器,那么可以使用-XX:+UseG1GC开关。

以下是一个启动 Java2Demo 程序的命令行示例,这个程序包含在下载得到的 JDK 演示和示例程序包之中:

java -Xmx50m -Xms50m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar
c:\javademos\demo\jfc\Java2D\Java2demo.jar

关键的命令行开关

  • -XX:+UseG1GC:告诉 JVM 使用 G1 垃圾收集器。

  • -XX:MaxGCPauseMillis=200:设置 GC 停顿时间的最大目标值。这不是一个硬性目标,JVM 将尽最大努力达成这个目标。因此,有时候并不能满足目标停顿时间。默认值为 200 毫秒。

  • -XX:InitiatingHeapOccupancyPercent=45:启动并发 GC 周期的(整个)堆内存占用率的百分比阈值。G1 收集器会根据整个堆内存的占用情况,而不是某个年代的占用情况,来触发一次并发的 GC 周期。若取值为 0,则表示“执行常量 GC 周期”。默认值为 45(也就是说,堆内存的占用率为 45%)。

最佳实践

以下是一些在使用 G1 收集器时应该遵循的最佳实践。

不要设置年轻代的大小

如果通过-Xmn选项来显式地设置年轻代的大小,那么就会干预 G1 收集器的默认行为。

  • G1 将不再会遵守垃圾收集的停顿时间目标。因此,大体上来说,设置年轻代的大小将会禁用停顿时间目标。
  • G1 不再能够根据需要扩展和缩减年轻代的内存空间。因为大小已经固定了,所以就不能改变大小。

响应时间的指标

应该设置XX:MaxGCPauseMillis=<N>选项,而不应该使用平均响应时间(ART)作为性能指标,这个设置值能够满足 90% 或更高的目标时间。这就意味着,在发起请求的所有用户中,至少有 90% 的用户经历的响应时间不会高于目标时间。注意,停顿时间只是一个目标,并不总是能够保证满足的。

什么是排空失败?

在垃圾收集期间,如果 JVM 在处理幸存对象和晋升对象时耗尽堆内存区域,那么便会发生晋升失败错误。因为堆内存已经达到最大容量,所以不能扩展容量。当使用-XX:+PrintGCDetails开关时,这种错误在 GC 日志中表示为to-space overflow。这样会付出昂贵的代价!

  • 由于必须释放内存空间,因此 GC 仍然需要继续运行。
  • 未能成功复制的对象必须就地老年化。
  • 对 CSet 中的堆内存区域的 RSet 进行的任何更新都必须重新生成。
  • 所有这些步骤的代价都非常昂贵!

如何避免排空失败

为了避免排空失败,可以考虑以下选项:

  • 增加堆内存的大小:
    • 增加-XX:G1ReservePercent=n选项的值,默认值为10。
    • G1 会创建一个错误最高上限,试图预留一些备用的空闲内存,以防需要更多的“to-space”空间。
  • 更早地启动标记周期。
  • 使用-XX:ConcGCThreads=n选项,增加标记线程的数量。

G1 垃圾收集器完整的命令行开关列表

以下是 G1 垃圾收集器完整的命令行开关列表。注意,你应该遵循上文强调的最佳实践。

选项和默认值 描述
-XX:+UseG1GC 使用垃圾优先(G1)收集器。
-XX:MaxGCPauseMillis=n 设置 GC 停顿时间的最大目标值。这不是一个硬性目标,JVM 将尽最大努力达成这个目标。
-XX:InitiatingHeapOccupancyPercent=n 启动并发 GC 周期的(整个)堆内存占用率的百分比阈值。垃圾收集器(例如:G1)会根据整个堆内存的占用情况,而不是某个年代的占用情况,来触发一次并发的 GC 周期。若取值为 0,则表示“执行常量 GC 周期”。默认值为 45。
-XX:NewRatio=n 新生代和老年代的大小比率。默认值为 2。
-XX:SurvivorRatio=n Eden 区和 Survivor 区的大小比率。默认值为 8。
-XX:MaxTenuringThreshold=n 对象晋升至老年代的最大年龄阈值。默认值为 15。
-XX:ParallelGCThreads=n 在并行阶段期间,垃圾收集器能够使用的线程数量。默认值会随着 JVM 的运行平台变化而变化。
-XX:ConcGCThreads=n 并发垃圾收集器将会使用的线程数量。默认值会随着 JVM 的运行平台变化而变化。
-XX:G1ReservePercent=n 设置需要预留的堆内存总量,可以作为 GC 的错误最高上限,以便于减少晋升失败的发生概率。默认值为 10。
-XX:G1HeapRegionSize=n G1 收集器会将 Java 的堆内存分割成若干个大小相同的区域。这个选项可以设置各个子区域的大小。JVM 会根据堆内存的大小自动确定这个参数的默认值。最小值为 1Mb,最大值为 32Mb。