JVM G1

在新项目使用到了G1

为什么使用 G1 , 在JDK8之后的版本中,G1 将会成为默认的 GC , 那么了解和使用 G1 是个不错的学习方向。在当前时间点:2025年5月20日时,JDK 版本已经来到了以下这个阶段

  • 25 in development
  • 24 GA 2025/03/18

那么在后续的版本中还有 ZGC / Shenandoah / Epsilon GC , 其中 CMS 在 JDK9 中弃用,在 14 中移除

为什么要有 G1

G1 的主要解决两个关键点:

  1. 可预测的暂停时间
  2. 软目标

可预测的暂停时间

之前的 GC : CMS / Parallel GC 在执行 标记-清扫 / 标记-复制 时,需要一次性扫描大量的对象,导致 STW 的时长不可控,波动大。

G1 的处理方案是:

  • 将堆分割为大量大小相同的块 Region ,每个大小在 [1,32] MB 之间,可根据堆大小自动调整
  • 按 Region 为单位进行收集,在一次 GC 暂停周期内,只收集一部分最值钱的 Region 而不是全部堆
  • 增量式完成老年代回收,将一次完整的老年代回收拆分成多次小规模的 Region 回收,每次都尽量控制在设定的时间窗口内
  • 历史预测模型:G1 会根据前几次 GC 的耗时,动态估算 “回收 N 个 Region” 大致需要多长时间,从而在每次 GC 之前决定这次回收多少 Region,才能逼近设定的暂停时间目标。

好处:每次 GC 暂停时只处理有限的 Region , 能够较准确估算清理大约需要的耗时,从而让暂停时间可预测。也更容易达到 用户在启动参数中通过 -XX:MaxGCPauseMillis= 指定的最大暂停时间目标

G1 会“预演”——根据历史数据预测这次 GC 的停顿耗时,并据此调整本次 GC 的工作量,使得每次停顿都尽可能接近我们想要的那个值。

软目标

尽最大努力去满足,但在内存压力,对象分配速率极高或堆碎片严重时,也可能超出目标

因此,G1 对暂停时间的管控是一种“努力达成但不绝对保证”的方式——这就是“软目标(Soft-Goal)”的含义

切割

Region 区域大小是在 JVM 启动时计算和定义的。它基于尽可能接近 2048 个区域的原则,每个区域的大小为 2 的幂,介于 1 到 64 MB 之间。更简单地说,对于一个 12 GB 的堆:

  • 12288 MB / 2048 个区域 = 6 MB - 这不是 2 的幂
  • 12288 MB / 8 MB = 1536 个区域 - 通常太低
  • 12288 MB / 4 MB = 3072 个区域 - 可接受

img

也可以选择通过 -XX:G1HeapRegionSize 显式指定区域大小。设置区域大小时,务必了解堆大小比将创建的区域数量,因为区域数量越少,G1 的灵活性就越低,扫描、标记和收集每个区域所需的时间也就越长。在所有情况下,空区域都会被添加到一个无序链表中,也称为“空闲列表”。

The flags are: 这些标志是:

-Xloggc:/path/to/gc.log -Xloggc:/路径/到/gc.log Path where the GC logs are written GC 日志写入的路径
-XX:+UseGCLogFileRotation Enable GC log file rotation 启用 GC 日志文件轮换
-XX:NumberOfGCLogFiles= Number of rotated GC logs files to retain 要保留的轮换 GC 日志文件数量
-XX:GCLogFileSize= -XX:GCLogFileSize = Size of each GC logs file to initiate rotation 启动轮换的每个 GC 日志文件的大小
-XX:+PrintGCDetails Detailed GC log 详细的 GC 日志
-XX:+PrintGCDateStamps -XX:+打印 GCDateStamps Actual date and timestamp of the collection 收集的实际日期和时间戳
-XX:+PrintGCApplicationStoppedTime Amount of time the application stopped during GC 应用程序在 GC 期间停止的时间量
-XX:+PrintGCApplicationConcurrentTime Amount of time the application ran between GCs 应用程序在 GC 之间运行的时间量
-XX:-PrintCommandLineFlags Prints all the command line flags in the GC log 在 GC 日志中打印所有命令行标志

The flags are: 这些标志是:

-XX:+PrintAdaptiveSizePolicy Details about the collector ergonomics 关于收集器人体工程学的详细信息
-XX:+PrintTenuringDistribution Survivor space usage and distribution Survivor 空间使用及分配
-XX:+PrintReferenceGC -XX:+打印参考 GC Time spent processing references 处理参考文献所花的时间

最后,我们还有诊断和实验标志。这些标志可以添加大量日志记录,应仅在必要时以及尝试调试特定问题时使用。

-XX:+UnlockDiagnosticVMOptions -XX:+解锁诊断虚拟机选项
-XX:+G1SummarizeConcMark Summarizes Concurrent Mark at JVM exit 总结 JVM 退出时的并发标记
-XX:+G1PrintHeapRegions Print the heap regions selected for allocation, cleanup, reuse, compact, cset, commit, failure, etc… 打印选择用于分配、清理、重用、压缩、cset、提交、失败等的堆区域…
-XX:+G1PrintRegionLivenessInfo Prints previous and next liveness data per Old region before and after every concurrent mark cycle 在每个并发标记周期之前和之后打印每个旧区域的上一个和下一个活跃度数据
-XX:+G1SummarizeRSetStats -XX:G1SummarizeRSetStatsPeriod=1 Print RSet processing information every X, where X is measured in GC cycles 每 X 次打印 RSet 处理信息,其中 X 以 GC 周期为单位
-XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 -XX:+打印安全点统计信息 -XX:打印安全点统计信息计数=1-XX:+LogVMOutput-XX:LogFile=/path/to/gc.log -XX:LogFile = /路径/到/gc.log Prints the reason and some details about safepoint synchronization. Can control how many events to collect before printing. By default, logs to STDOut - LogVMOutput can push it to a file 打印原因以及有关安全点同步的一些详细信息。可以控制打印前收集的事件数量。默认情况下,日志记录到 STDOut - LogVMOutput 可以将其推送到文件
-XX:+UnlockExperimentalVMOptions -XX:+解锁实验虚拟机选项
-XX:G1LogLevel=fine, finer, finest -XX:G1LogLevel=fine,更精细,最精细 Increases logging verbosity on collections 增加集合的日志详细程度
-XX:+G1TraceEagerReclaimHumongousObjects Prints details about live and dead Humongous objects during each collection 打印每次收集期间存活和死亡的 Humongous 对象的详细信息
-XX:+G1ConcRegionFreeingVerbose Debug JVM 调试 JVM

最后,我们还有诊断和实验标志。这些标志可以添加大量日志记录,应仅在必要时以及尝试调试特定问题时使用。

-XX:+UnlockDiagnosticVMOptions -XX:+解锁诊断虚拟机选项
-XX:+G1SummarizeConcMark Summarizes Concurrent Mark at JVM exit 总结 JVM 退出时的并发标记
-XX:+G1PrintHeapRegions Print the heap regions selected for allocation, cleanup, reuse, compact, cset, commit, failure, etc… 打印选择用于分配、清理、重用、压缩、cset、提交、失败等的堆区域…
-XX:+G1PrintRegionLivenessInfo Prints previous and next liveness data per Old region before and after every concurrent mark cycle 在每个并发标记周期之前和之后打印每个旧区域的上一个和下一个活跃度数据
-XX:+G1SummarizeRSetStats -XX:G1SummarizeRSetStatsPeriod=1 Print RSet processing information every X, where X is measured in GC cycles 每 X 次打印 RSet 处理信息,其中 X 以 GC 周期为单位
-XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 -XX:+打印安全点统计信息 -XX:打印安全点统计信息计数=1-XX:+LogVMOutput-XX:LogFile=/path/to/gc.log -XX:LogFile = /路径/到/gc.log Prints the reason and some details about safepoint synchronization. Can control how many events to collect before printing. By default, logs to STDOut - LogVMOutput can push it to a file 打印原因以及有关安全点同步的一些详细信息。可以控制打印前收集的事件数量。默认情况下,日志记录到 STDOut - LogVMOutput 可以将其推送到文件
-XX:+UnlockExperimentalVMOptions -XX:+解锁实验虚拟机选项
-XX:G1LogLevel=fine, finer, finest -XX:G1LogLevel=fine,更精细,最精细 Increases logging verbosity on collections 增加集合的日志详细程度
-XX:+G1TraceEagerReclaimHumongousObjects Prints details about live and dead Humongous objects during each collection 打印每次收集期间存活和死亡的 Humongous 对象的详细信息
-XX:+G1ConcRegionFreeingVerbose Debug JVM 调试 JVM
- the End -
0%