随着JDK 15发布,最新版本的ZGC现在可以投入生产了。简而言之,ZGC是一个可伸缩的低延迟垃圾收集器,最大GC暂停时间为10毫秒,能够处理从几兆字节到多TB的堆,最大吞吐量降低了15%。
JVM垃圾收集器
到目前为止,JVM引入了一个有趣的垃圾收集器算法列表,下面列出了最重要的算法和简短的描述,让我们记住它们。
- 串行(低内存占用):它使用单个线程来完成工作。它适用于单处理器计算机,并且针对内存不足(通常是嵌入式系统)进行了优化。
- 并行(吞吐量收集器):它并行进行次要收集,以减少垃圾收集的开销。它是为在多处理器硬件上运行的中型到大型数据集应用程序而构建的。
- CMS(并发标记扫描收集器):它旨在缩短垃圾收集器的暂停时间。专为具有大量长寿命对象或大量长期使用期限的应用程序而设计。CMS收集器是generational的。
- G1(吞吐量/等待时间平衡): Garbage-First是服务器样式的垃圾收集器,设计用于具有大内存的多处理器计算机。它是一个压缩收集器(它压缩得足够避免使用没有细粒度的列表进行分配)。
- ZGC(低延迟)
比较它们很有趣。ZGC可同时执行所有繁重的操作,而其他算法则无法做到(更多详细信息请参见下文)。
深入Z垃圾收集器
ZGC是并发的低延迟算法,除了线程堆栈扫描外,它所有并发的操作(标记,压缩,参考处理,重定位集选择,StringTable清理,JNI WeakRef清理,JNI GlobalRefs扫描和类卸载)。这使得该算法对于低延迟确实非常有用。
值得一提的是,当前,暂停时间并不随堆大小而增加,但是,暂停时间却随根集root-set大小(您的应用程序正在使用的Java线程数)而增加。
从算法的角度来看,它是一个并发收集器,它在Java线程继续执行的同时完成了所有繁重的工作。这是一个基于区域的收集器,这意味着将堆划分为较小的区域,并且压缩工作将集中在这些区域的子集上,即垃圾最多的区域。它是NUMA感知的,由于CPU有本地内存,因此可以减少延迟。它使用彩色指针和负载屏障,将在以下各节中详细介绍。它是一个单一的一代收集器,它没有以前回收机制的年轻或年老代。
ZGC阶段
ZGC的GC周期分为三个暂停。
在第一阶段(暂停标记开始)中,ZGC遍历对象图以将对象标记为活动或无用。此阶段还包括实时数据的重新映射。
第二阶段是“暂停标记结束”,在此阶段完成参考预处理。在该阶段还完成了类卸载和重定位集的选择。
暂停重定位启动是最后一个阶段,在此阶段要进行大量的压缩堆工作。
- 彩色的指针
- 负载屏障
微调选项
如果要使用ZGC算法,JDK15之前版本必须解锁实验选项:
-XX:+ UnlockExperimentalVMOptions -XX:+ UseZGC
预先从JDK 15开始,只需指定以下即可使用它:
-XX:+UseZGC
ZGC的设计易于调整。以下是特定的ZGC选项的列表:

为了了解使用的时间并了解有关算法行为的一些数字,打印垃圾收集器日志是很好的,只需在选择ZGC来查看简单日志时添加以下命令:
-XX:+UseZGC -Xmx
或者,如果要打印更多信息的垃圾收集器日志,请执行以下操作:
-XX:+UseZGC -Xmx
现在,让我们开始看看最有趣的调优选项。
- 设置堆大小
-XX:+UseZGC -Xmx
- 设置并发GC线程
-XX:+UseZGC -Xmx
- 将未使用的内存返回到操作系统
-XX:+UseZGC -Xmx
- 在Linux上启用大页面
-XX:+UseZGC -Xms16G -Xmx16G -XX:+UseLargePages
- 在Linux上启用透明的大页面
-XX:+UseZGC -… -XX:+UseLargePages -XX:+UseTransparentHugePages
在这种情况下,我强烈建议您在应用程序中对其进行试验,并注意峰值是否发生,如果发生峰值,也许这不是您的情况的选择。
- 启用NUMA支持
-XX:+UseZGC -Xmx
或
-XX:+UseZGC -Xmx
总结
ZGC团队的路线图吸引了我两件事。
首先是团队正在努力将最大暂停时间减少到1 ms。线程堆栈扫描将同时进行,这也意味着暂停时间不会随根集大小的增加而增加(JEP 376)。
其次,它们将使ZGC成为世代相传的产品,因为大多数对象都是短命的,这将是另一个不错的改进。