JEP 304:垃圾收集器接口
概括
通过引入干净的垃圾收集器 (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 中需要更改的所有位置。
描述
CollectedHeap
GC 接口将由每个垃圾收集器需要实现的现有类定义。该类CollectedHeap
将驱动垃圾收集器和 HotSpot 其余部分之间交互的大部分方面(在实例化之前需要一些实用程序类CollectedHeap
)。更具体地说,垃圾收集器实现必须提供:
- 堆,一个子类
CollectedHeap
- 障碍集, 的子类
BarrierSet
,它实现了运行时的各种障碍 - 一个实现
CollectorPolicy
- 的实现
GCInterpreterSupport
,它为解释器实现了 GC 的各种障碍(使用汇编指令) - 的实现
GCC1Support
,它为 C1 编译器实现了 GC 的各种障碍 - 的实现
GCC2Support
,它为 C2 编译器实现了 GC 的各种障碍 - 最终 GC 特定参数的初始化
- 设置a
MemoryService
、相关的内存池、内存管理器等。
在多个垃圾收集器之间共享的实现细节的代码应该存在于辅助类中。这样,不同的 GC 实现就可以轻松地使用它。例如,可能有一个帮助程序类实现了卡表支持的各种障碍,并且任何需要卡表后障碍的 GC 都会调用该帮助程序类的相应方法。通过这种方式,该接口可以灵活地实现全新的障碍,同时允许以混合搭配的方式重用现有代码。
备择方案
另一种选择是继续使用当前的架构。这很可能会持续更长的时间,但会阻碍未来新 GC 算法的开发和旧算法的删除。
测试
这纯粹是重构。之前有效的一切都需要在之后有效,并且性能不应该倒退。运行标准回归测试套件就足够了; 无需开发新的测试。
风险和假设
风险较低,这主要是HotSpot内部代码的重构。存在性能可能受到损害的风险,例如,如果引入额外的虚拟呼叫。这种风险可以通过持续的性能测试来减轻。
依赖关系
此 JEP 将有助于JEP 291:弃用并发标记扫描 (CMS) 垃圾收集器,因为它提供了一种隔离它的方法,并允许其他人在需要时对其进行维护。
此 JEP 还将帮助JEP 189:Shenandoah:超低暂停时间垃圾收集器,并使其更改不那么具有侵入性。