跳到主要内容

JEP 333:ZGC:可扩展的低延迟垃圾收集器(实验性)

概括

Z 垃圾收集器也称为 ZGC,是一种可扩展的低延迟垃圾收集器。

目标

  • GC暂停时间不应超过10ms
  • 处理大小范围从相对较小(几百兆字节)到非常大(许多 TB)的堆
  • 与使用 G1 相比,应用程序吞吐量减少不超过 15%
  • 利用彩色指针和负载屏障为未来的 GC 功能和优化奠定基础
  • 最初支持的平台:Linux/x64

我们有强烈的雄心来实现大量相关工作负载的这些目标。同时,我们要承认,我们并不认为这些目标是每个可想象的工作负载的硬性要求。

非目标

为 Linux/x64 以外的平台提供工作实现并不是我们的目标。如果有足够的需求,可以稍后添加对其他平台的支持。

动机

垃圾收集是 Java 的主要优势之一。但是,当垃圾收集暂停时间过长时,它们就会开始对应用程序响应时间产生负面影响。通过消除或大幅减少 GC 暂停的长度,我们将使 Java 成为对更广泛的应用程序来说更具吸引力的平台。

此外,现代系统中可用的内存量持续增长。用户和应用程序开发人员希望 JVM 能够以高效的方式充分利用此内存,并且不会出现较长的 GC 暂停时间。

描述

乍一看,ZGC 是一个并发、单代、基于区域、NUMA 感知、压缩的收集器。 Stop-the-world 阶段仅限于根扫描,因此 GC 暂停时间不会随着堆或活动集的大小而增加。

ZGC 的核心设计原则/选择是将负载屏障与彩色对象指针(即彩色oops)结合使用。这使得 ZGC 能够在 Java 应用程序线程运行时执行并发操作,例如对象重定位。从 Java 线程的角度来看,在 Java 对象中加载引用字段的行为会受到加载屏障的影响。除了对象地址之外,彩色对象指针还包含负载屏障使用的信息,以确定在允许 Java 线程使用该指针之前是否需要采取某些操作。例如,对象可能已被重新定位,在这种情况下,负载屏障将检测到情况并采取适当的操作。

与其他技术相比,我们相信彩色指针方案提供了一些非常有吸引力的特性。尤其:

  • 它允许我们在重定位/压缩阶段回收和重用内存,然后再修复指向回收/重用区域的指针。这有助于降低总体堆开销。这也意味着不需要实现单独的标记紧凑算法来处理完整GC。

  • 它允许我们拥有相对较少且简单的 GC 屏障。这有助于降低运行时开销。这也意味着在我们的解释器和 JIT 编译器中更容易实现、优化和维护 GC 屏障代码。

  • 目前,我们将标记和重定位相关信息存储在彩色指针中。然而,该方案的多功能性允许我们存储任何类型的信息(只要我们可以将其放入指针中),并让负载屏障根据该信息采取它想要的任何操作。我们相信这将为许多未来的功能奠定基础。举一个例子,在异构内存环境中,这可用于跟踪堆访问模式,以指导 GC 重定位决策,将很少使用的对象移至冷存储。

表现

使用 SPECjbb® 2015 [1] 进行了定期性能测量。从吞吐量和延迟的角度来看,性能看起来都不错。下面是使用 128G 堆的复合模式下比较 ZGC 和 G1 的典型基准测试分数(以百分比表示,根据 ZGC 的 max-jOPS 进行归一化)。

(越高越好)

ZGC
max-jOPS: 100%
critical-jOPS: 76.1%

G1
max-jOPS: 91.2%
critical-jOPS: 54.7%

以下是同一基准测试中的典型 GC 暂停时间。 ZGC 设法保持远低于 10 毫秒的目标。请注意,具体数字可能会有所不同(向上或向下,但不会很大),具体取决于所使用的具体机器和设置。

(越低越好)

ZGC
avg: 1.091ms (+/-0.215ms)
95th percentile: 1.380ms
99th percentile: 1.512ms
99.9th percentile: 1.663ms
99.99th percentile: 1.681ms
max: 1.681ms

G1
avg: 156.806ms (+/-71.126ms)
95th percentile: 316.672ms
99th percentile: 428.095ms
99.9th percentile: 543.846ms
99.99th percentile: 543.846ms
max: 543.846ms

还对各种其他 SPEC® 基准测试和内部工作负载进行了临时性能测量。一般来说,ZGC 能够维持个位数毫秒的暂停时间。

[1] SPECjbb® 2015 是标准绩效评估公司 (spec.org) 的注册商标。实际结果并不表示为合规,因为 SUT 可能不满足 SPEC 对一般可用性的要求。

局限性

ZGC 的初始实验版本将不支持类卸载。默认情况下将禁用ClassUnloading和选项。ClassUnloadingWithConcurrentMark启用它们不会产生任何效果。

此外,ZGC 最初不会支持 JVMCI(即 Graal)。如果EnableJVMCI启用该选项,将打印一条错误消息。

这些限制将在本项目的后期阶段得到解决。

构建和调用

按照惯例,构建系统默认禁用 JVM 中的实验性功能。 ZGC 作为一项实验性功能,因此不会出现在 JDK 构建中,除非在编译时使用配置选项显式启用--with-jvm-features=zgc

(ZGC 将出现在 Oracle 生成的所有 Linux/x64 JDK 版本中)

JVM 中的实验性功能也需要在运行时显式解锁。要启用/使用 ZGC,需要以下 JVM 选项-XX:+UnlockExperimentalVMOptions -XX:+UseZGC

有关如何设置和调整 ZGC 的更多信息,请参阅ZGC 项目 Wiki 。

备择方案

  • 一个明显的替代方案是向 G1 添加并发压缩功能。这种替代方案被广泛原型化,但最终被放弃。我们发现将这个功能硬塞到一个从未为此目的而设计的代码库中,同时又保持 G1 的稳定性和其他良好特性是不可行的。

  • 理论上的替代方案是以某种方式改进 CMS。然而,有几个原因导致基于 CMS 算法的低延迟收集器既不是一个有吸引力的也不可行的选择。原因包括不支持压缩、未绑定的注释阶段、复杂的代码库以及它已被弃用的事实 ( JEP 291 )。

  • Shenandoah 项目正在探索使用 Brooks 指针来实现并发操作(JEP 189)。

测试

我们现有的大多数功能和压力测试与收集器无关,并且可以按原样重用。将添加针对 ZGC 特定属性和功能的其他测试。

依赖关系