JEP 189:Shenandoah:一种低暂停时间的垃圾收集器(实验性)
概述
新增一个名为 Shenandoah 的垃圾回收 (GC) 算法,该算法通过与运行中的 Java 线程同时进行疏散工作来减少 GC 暂停时间。使用 Shenandoah 时,暂停时间与堆大小无关,这意味着无论您的堆是 200 MB 还是 200 GB,暂停时间都将是相同且一致的。
非目标
这并不是唯一的 GC(垃圾收集器)来统领一切。还有其他垃圾收集算法更加注重吞吐量或内存占用,而非响应速度。Shenandoah 是一种适用于重视响应速度和可预测的短暂停顿的应用程序的算法。其目标并非解决所有 JVM 暂停问题。由于 GC 以外的原因(例如安全点时间 (TTSP) 问题或监视器膨胀)导致的暂停时间不在本 JEP 的范围内。
成功指标
如果可以保持较短的 GC 暂停时间,该项目将取得成功。
描述
现代机器比以往任何时候都拥有更多的内存和更多的处理器。服务级别协议(SLA)应用程序保证 10-500 毫秒的响应时间。为了达到该目标的下限,我们需要足够高效的垃圾收集算法,以允许程序在可用内存中运行,同时也需要进行优化,以确保中断运行程序的时间不超过几十毫秒。Shenandoah 是一个开源的低暂停时间收集器,用于 OpenJDK,旨在让我们更接近这些目标。
Shenandoah 通过交换并发的 CPU 周期和空间来减少暂停时间。我们在每个 Java 对象中添加了一个间接指针,这使得垃圾回收线程可以在 Java 线程运行的同时对堆进行压缩。标记和压缩是并发执行的,因此我们只需要暂停 Java 线程足够长的时间来扫描线程栈,以找到并更新对象图的根节点。
Shenandoah 算法在这篇 PPPJ2016 论文中有深入的描述:Shenandoah: An open-source concurrent compacting garbage collector for OpenJDK。
Shenandoah 已经实现,并且将由 Red Hat 为 aarch64 和 amd64 提供支持。
Shenandoah 的持续开发工作是在 OpenJDK 的 Shenandoah 项目中进行的。更多关于当前开发流程、实现细节以及可用性的信息,请参阅 Shenandoah 维基页面。
替代方案
Zing/Azul 拥有一个无暂停的垃圾收集器,但这项工作并未贡献给 OpenJDK。
ZGC 具有基于彩色指针的低暂停收集器。我们期待比较这两种策略的性能。
G1 垃圾收集器进行一些并行和并发的工作,但它并不进行并发疏散(concurrent evacuation)。
CMS 进行并发标记,但它会在暂停期间执行年轻代复制,并且从不压缩老年代。这会导致在老年代中管理空闲空间花费更多时间,并且会出现碎片问题。
构建与调用
作为实验性功能,Shenandoah 将需要在命令行中添加 -XX:+UnlockExperimentalVMOptions
。Shenandoah 的构建系统会在不支持的配置上自动禁用构建。下游构建者可以选择通过 --with-jvm-features=-shenandoahgc
在其他受支持的平台上禁用 Shenandoah 的构建。
要启用/使用 Shenandoah GC,需要以下 JVM 选项:-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC
。
有关如何设置和调整 Shenandoah GC 的更多信息,请参阅 Shenandoah wiki 页面。
测试
Red Hat 已经为我们的重要应用程序进行了广泛的测试。我们已经开发了许多 Shenandoah 特定的 jtreg 测试。Shenandoah 从 Fedora 24 开始在 Fedora 中提供,并在 Rhel 7.4 中作为技术预览版提供。使用 -XX:+UseShenandoahGC
运行标准的 OpenJDK 测试应该就足够了。
风险与假设
GC 接口(JEP 304)被集成到了 JDK 11 中,此后 GC 接口得到了许多扩展与改进。这最大限度地降低了将 Shenanodah 添加到 OpenJDK 代码库的风险。除此之外,任何无法合理解决的 Shenandoah 特定代码路径都将通过 #ifdef INCLUDE_SHENANDOAHGC
或类似机制进行保护。Shenandoah GC 最初会被标记为实验性功能,因此除了需要使用 -XX:+UseShenandoahGC
之外,还需要添加 -XX:+UnlockExperimentalVMOptions
。