JEP 189: Shenandoah: A Low-Pause-Time Garbage Collector (Experimental) | Shenandoah:低暂停时间垃圾收集器(实验性)
摘要
添加一个新的名为 Shenandoah 的垃圾收集(GC)算法,该算法通过与正在运行的 Java 线程并发执行清除工作来减少 GC 暂停时间。使用 Shenandoah 的暂停时间与堆大小无关,这意味着无论您的堆大小是 200MB 还是 200GB,您都将获得相同且一致的暂停时间。
非目标
这并非一种能够一统天下的垃圾收集器。还有其他垃圾收集算法优先考虑吞吐量或内存占用而不是响应性。Shenandoah 是一种适用于重视响应性和可预测短暂停时间的应用程序的算法。目标并非解决所有 JVM 暂停问题。由于非 GC 原因(如 Time To Safe Point(TTSP)问题或监视器膨胀)导致的暂停时间不在本 JEP 的范围内。
成功标准
如果我们能够保持一致的短 GC 暂停时间,则该项目将取得成功。
描述
现代机器拥有比以往任何时候都多的内存和处理器。服务水平协议(SLA)应用保证的响应时间范围在 10-500 毫秒之间。为了达到该目标的下限,我们需要垃圾收集算法足够高效,以允许程序在可用内存中运行,但也要优化算法,确保它永远不会中断正在运行的程序超过几毫秒。Shenandoah 是为 OpenJDK 设计的开源低暂停时间收集器,旨在帮助我们更接近这些目标。
Shenandoah 通过交换并发 CPU 周期和空间来改进暂停时间。我们在每个 Java 对象上添加了一个间接指针,这使得 GC 线程能够在 Java 线程运行时压缩堆。标记和压缩是并发进行的,所以我们只需要暂停 Java 线程足够长的时间来扫描线程栈,以找到并更新对象图的根。
Shenandoah 算法在 这篇 PPPJ2016 论文 中进行了深入描述。
Shenandoah 已经被实现,Red Hat 将为 aarch64 和 amd64 提供支持。
Shenandoah 的持续开发在 OpenJDK 的 Shenandoah 项目中进行。更多关于当前开发流程、实现细节和可用性的详细信息,请参见 Shenandoah 维基页面。
替代方案
Zing/Azul 有一个无暂停的收集器,但是这项工作并未贡献给 OpenJDK。
ZGC 有一个基于着色指针的低暂停收集器。我们期待比较这两种策略的性能。
G1 进行了一些并行和并发工作,但它并不进行并发清除。
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 接口进行了许多扩展和改进。这减少了将 Shenandoah 添加到 OpenJDK 源代码库中的风险。除此之外,任何无法合理处理的特定于 Shenandoah 的代码路径都将由 #ifdef INCLUDE_SHENANDOAHGC
或类似机制进行保护。Shenandoah GC 最初将被标记为实验性功能,因此除了 -XX:+UseShenandoahGC
之外,还需要 -XX:+UnlockExperimentalVMOptions
。