关于java:译-垃圾收集器算法ZGC

3次阅读

共计 2608 个字符,预计需要花费 7 分钟才能阅读完成。

原文地址:The Z Garbage Collector algorithm
原文作者:Jesús Navarrete
译者:maybelence

介绍

ZGC 最早作为 JDK11 中的预览个性公布,去年 9 月 15 号,
随着 JDK 15 的正式公布,也带来了 ZGC 的正式版本。

ZGC 是可伸缩的低提早垃圾收集器,最大 GC 暂停工夫为 10 毫秒,可能解决从几兆字节到几 TB 的堆,最大吞吐量升高了 15%。

JVM 垃圾收集器

截止目前,JVM 曾经引入了一系列乏味的垃圾收集算法。上面列出了几个最重要的垃圾收集算法:

  • 串行(低内存占用):应用单线程来工作,实用于单处理器计算机,并且针对内存不足(嵌入式零碎)进行了优化。
  • 并行(吞吐量收集器):并行进行主要收集,以缩小垃圾收集的开销。实用于多处理器硬件上运行的中型到大型数据集应用程序。
  • CMS(并发标记扫描收集器):具备较短的垃圾收集器暂停工夫。专为具备大量长寿命对象或大量应用期限的应用程序而设计。
  • G1(吞吐量 / 等待时间均衡):Garbage-First 是服务器款式的垃圾收集器,实用于具备大内存的多处理器计算机。它试图以高概率满足 GC 暂停工夫指标,同时实现高吞吐量。全堆操作(例如全局标记)与应用程序线程同时执行。这样能够避免与堆或流动数据大小成比例的中断。
  • ZGC(低提早)

串行和并行称为 stop of the world 算法。CMS 在 JDK 9 中已弃用,用 G1 代替。

这里要强调 ZGC 能够并行处理所有沉重的操作,而其余算法却无奈做到(具体细节见下文)。


深刻理解 ZGC

ZGC 是一种并发的低提早算法,除了线程堆栈扫描外,它所有其余操作(标记,压缩,参考解决,重定位集抉择,StringTable 清理,JNI WeakRef 清理,JNI GlobalRefs 扫描和类卸载)都是并行的。所以该算法对于低提早的确十分有用。

ZGC 暂停工夫并不随堆或流动大小而减少,而是与根汇合的一个子集的大小相干(您的应用程序正在应用的 Java 线程数)。也就是依然在 Stop-The-World 阶段扫描线程栈。 然而从 JDK 16 开始,对线程栈的扫描是并行处理的,也就是说在扫描栈的时候应用程序能够同时运行。

原作者写的时候是 JDK15 , 这里我补充了一下 JDK 16 对 ZGC 的变动

从算法的角度来看,它是一个并发收集器,它在 Java 线程继续执行的同时实现了所有沉重的工作。它是一个基于区域的收集器,这意味着将堆划分为较小的区域,并且压缩工作将集中于这些区域的子集,即那些垃圾最多的区域。它是 NUMA 感知 的,因为 CPU 具备本地内存,因而能够缩小提早。它应用黑白指针和负载屏障,将在以下各节中进行具体介绍。而且它是一个繁多的一代收集器,它没有以前回收机制的年老代或老年代。

ZGC 阶段

ZGC 的 GC 周期分为三个阶段。

在第一阶段(暂停标记开始)中,ZGC 遍历对象图以将对象标记为流动或无用。此阶段还包含从新映射实时数据。

第二阶段是“暂停标记完结”,此阶段实现参考预处理。在该阶段还实现了类卸载和重定位集的抉择。

暂停重定位启动是最初一个阶段,在此阶段要进行大量的压缩堆工作。

黑白指针

这是 ZGC 中的外围设计概念。该算法应用 64 位对象指针中的一些未应用的位来存储一些元数据,从而能够查找,标记,定位和从新映射对象。下图显示了 64 位对象指针和每个位的含意。

内存屏障

它是 JAVA 即时编译器在某些重要地位注入的代码。目标是查看加载的对象援用是否具备不良的色彩。当线程从堆中加载对象援用时,将运行负载屏障代码。

调优选项

从 JDK 11 到 JDK 15 发行版,如果要应用 ZGC 算法,必须解锁试验选项:

-XX:+UnlockExperimentalVMOptions -XX:+UseZGC

如果是 JDK 15 之后的版本,只须要指定一下内容:

-XX:+UseZGC

ZGC 的设计易于调整。上面是特定的 ZGC 选项的列表:

为了晓得应用的工夫并查看无关算法行为的一些数字,咱们能够打印一些垃圾收集器日志,抉择 ZGC 来查看简略日志时,只需增加以下命令即可:

-XX:+UseZGC -Xmx<size> -Xlog:gc

如果您想打印带有更多详细信息的垃圾收集器日志,能够执行以下操作:

-XX:+UseZGC -Xmx<size> -Xlog:gc*

接下来让咱们看看其余乏味的调优选项。

设置堆大小

ZGC 中最重要的调整选项之一是设置最大堆大小 (-Xmx<size>)。咱们必须为咱们的应用程序找到正确的值,因为咱们不想失落内存,并且心愿在 GC 运行时容许咱们的应用程序有足够的空间用于流动对象和调配。以下是应用示例:

-XX:+UseZGC Xmx<size> 

设置 GC 并发线程

只管 ZGC 具备启发式性能,能够主动抉择此数字,但有时,依据咱们的应用程序,指定并发 GC 线程数可能会很乏味。此选项确定 GC 将占用多少 CPU,因而您必须小心要提供的容量。

将未应用的内存返回到操作系统

区别于其余的 GC 算法,ZGC 勾销提交未应用的内存,将其返回给操作系统。对于可能会占用内存的应用程序,这可能是必须的。如果要禁用此选项,则能够应用 -XX:-ZUncommit

-XX:+UseZGC -Xmx<size> -XX:-ZUncommit

在 Linux 上启用大页面

此选项可进步性能,而且没有任何隐患。惟一的问题是它须要 root 受权,这就是为什么它不是默认选项,并且可能无奈为您的应用程序启用它的起因。查看文档以正确设置此选项。它须要筹备一些货色,选项如下所示:

-XX:+UseZGC -Xms16G -Xmx16G -XX:+UseLargePages

在 Linux 上启用通明的大页面

不倡议将 Huges 页面用于对提早敏感的应用程序,只管它能够代替以前的调整选项。

-XX:+UseZGC -… -XX:+UseLargePages -XX:+UseTransparentHugePages

在这种状况下,我强烈建议您在应用程序中进行试验,并留神峰值,如果呈现峰值,那么您可能就无奈抉择这种状况。

启用 NUMA 反对

ZGC 在默认状况下启用 NUMA 反对。这会将 Java 堆调配定向到 NUMA 本地内存。JVM 能够主动禁用它,如果您须要显式笼罩行为,则能够应用选项 -XX:+ UseNUMA 或 -XX:-UseNUMA。

-XX:+UseZGC -Xmx<size> -XX:+UseNUMA

或者

-XX:+UseZGC -Xmx<size> -XX:-UseNUMA

该算法的 Wiki 页面上还有更多具体的信息。

正文完
 0