JEP 304: Garbage Collector Interface | 垃圾收集器接口
摘要
通过引入一个干净的垃圾收集器(GC)接口来提高不同垃圾收集器的源代码隔离。
目标
- 更好的 HotSpot 内部 GC 代码模块化
- 在不干扰当前代码库的情况下,更容易向 HotSpot 添加新的 GC
- 更容易在 JDK 构建中排除 GC
非目标
- 实际添加或删除 GC 不是目标。
- 这项工作将朝着在 HotSpot 中构建时隔离 GC 算法的进展迈出一步,但完全实现构建时隔离并不是目标(这是另一个 JEP)。
成功度量
如果 GC 实现主要包含在各自的 src/hotspot/share/gc/$NAME
目录以及可能的 src/hotspot/cpu/share/gc/$NAME
目录中的源文件中,并且这些目录中的文件应最小化包括那些目录中的文件,则认为实现是成功的,而且应该有非常少的 GC 特定的 if
- else
分支。
由于此重构而导致的性能不应退化。
动机
每个垃圾收集器实现当前都由其 src/hotspot/share/gc/$NAME
目录中的源文件组成,例如 G1 在 src/hotspot/share/gc/g1
中,CMS 在 src/hotspot/share/gc/cms
中等。但是,有许多零散的部分分散在 HotSpot 源代码中。例如,大多数 GC 都需要实现某些屏障,这些屏障需要在运行时、解释器、C1 和 C2 中实现。这些屏障不包含在 GC 的特定目录中,而是在共享解释器、C1 和 C2 源代码中实现的(通常由长的 if
- else
链保护)。同样的问题也适用于例如诊断代码,如 MemoryMXBeans
。此源代码布局存在几个缺点:
- 对于 GC 开发人员,实现新的垃圾收集器需要了解所有这些不同的位置以及如何针对其特定需求进行扩展。
- 对于不是 GC 开发人员的 HotSpot 开发人员,很难找到给定 GC 的特定代码片段。
- 在构建时排除特定的垃圾收集器很困难。
#define INCLUDE_ALL_GCS
一直是一种仅使用串行收集器内置构建 JVM 的方法,但是该机制变得过于僵化。
更干净的 GC 接口将使实现新的收集器变得更加容易,使代码更加干净,并且更容易在构建时排除一个或多个收集器。添加新的垃圾收集器应该是实现一组良好记录的接口,而不是找出 HotSpot 中需要更改的所有位置的问题。
描述
GC 接口将由现有类 CollectedHeap
定义,每个垃圾收集器都需要实现该类。 CollectedHeap
类将驱动垃圾收集器与 HotSpot 的大多数交互方面(在实例化 CollectedHeap
之前需要几个实用程序类)。具体而言,垃圾收集器实现必须提供:
- 堆,
CollectedHeap
的子类 - 屏障集,
BarrierSet
的子类,实现运行时的各种屏障 CollectorPolicy
的实现GCInterpreterSupport
的实现,该实现为解释器实现了 GC 的各种屏障(使用汇编指令)GCC1Support
的实现,该实现为 C1 编译器实现了 GC 的各种屏障GCC2Support
的实现,该实现为 C2 编译器实现了 GC 的各种屏障- 最终 GC 特定参数的初始化
- 设置
MemoryService
,相关的内存池、内存管理器等。
用于多个垃圾收集器之间共享实现细节的代码应存在于帮助程序类中。这样可以很容易地由不同的 GC 实现使用。例如,可以有一个帮助程序类,该类实现卡表支持的各种屏障,任何需要卡表后屏障的 GC 都会调用该帮助程序类的相应方法。这样,接口提供了实现全新屏障的灵活性,同时允许以混合和匹配的方式重用现有代码。
替代方案
另一个选择是继续使用当前的架构。这可能会在一段时间内起作用,但将阻碍新 GC 算法的未来开发和旧 GC 算法的删除。
测试
这仅是重构。在此之前,所有工作都需要正常工作,并且由于此操作而导致的性能不应退化。运行标准回归测试套件应足够;无需开发新测试。
风险和假设
风险很小,这主要是 HotSpot 内部代码的重构。例如,如果引入了额外的虚拟调用,则有可能损害性能。可以通过持续的性能测试来减轻此风险。
依赖关系
此 JEP 将有助于 JEP 291:弃用并发标记扫描(CMS)垃圾收集器,因为它提供了一种隔离它的方式,并允许其他人维护它(如果需要)。
此 JEP 还将有助于 JEP 189:Shenandoah:一种超低暂停时间垃圾收集器,并使其更改不那么侵入。