OpenJDK 17中的Shenandoah可实现亚毫秒级GC暂停


Redhat在 JDK 12 中发布了原始的 Shenandoah 垃圾收集器,它实现了并发堆疏散,解决了在不停止应用程序的情况下清理(可能很大)堆的主要问题。这个版本最终被移植到 JDK 11;在 JDK 14 中,实现了并发类卸载;在 JDK 16 中,我们添加了并发引用处理,这两者都进一步减少了垃圾收集操作的暂停时间。暂停下剩余的垃圾收集操作是线程堆栈处理,已经在JDK 17 中解决了这个问题。
下表显示了 JDK 11、JDK 16 和 JDK 17 中所有基准测试的平均暂停时间。 JDK 16 和 JDK 17 之间的差异显示了并发堆栈处理所实现的改进。与 JDK 11 的区别是为了完整性而显示的,包括与以前版本相比的各种其他改进:

JDK 11 1294 微秒
JDK 16  704 微秒
JDK 17  328 微秒
 

OpenJDK 17 中的并发线程处理
Java 程序在线程中执行,每个线程拥有一个栈:堆栈帧的列表,每个帧保存着局部变量、监视器以及与当前执行的方法相关的其他信息。最重要的是,在 Java 垃圾收集的上下文中,它保存对堆对象的引用(例如,引用类型化对象的局部变量)。
通过使用一种称为堆栈水印的机制(最初由 ZGC 开发人员实现)来实现这一点。中心观察是所有线程堆栈的操作都发生在最顶层的帧中:当前执行的方法。需要做的就是在堆栈帧被销毁时(例如,通过返回调用者,或通过抛出异常)协调 GC 线程与正在执行的线程,从而退出 GC 处理。这种协调是通过堆栈水印实现的,一个告诉我们堆栈的哪些部分可以安全扫描的指针,以及一个允许垃圾收集器处理返回的屏障。