
Go 1.25引入了一个新的实验性垃圾收集器,其速度比当前实现可快达 40%,为 GC 密集型工作负载带来了显著的性能提升。
这个新的垃圾收集器被称为 Green Tea,它使用与现有 GC 相同的标记-清除方法,但有一个关键区别:它不是在单个对象上操作,而是在内存页级别上工作。这意味着 Green Tea 在全局范围内扫描和跟踪整个页面,同时在每个页面内本地跟踪单个对象,而不是整个堆。
所有这些都使其更适合微架构。我们现在可以以更高的概率扫描更靠近的对象,因此我们可以更好地利用缓存而避免使用主存。同样,每页元数据更有可能在缓存中。跟踪页面而不是对象意味着工作列表更小,工作列表上的压力更小意味着更少的争用和更少的 CPU 停顿。
这种方法大大减少了标记整个堆所需的扫描次数,这是非常重要的,因为“垃圾收集器大约 90%的成本用于标记,只有大约 10%用于清除”,Go 贡献者 Michael Knyszek 和 Austin Clements 表示。
Knyszek 和 Clements 还解释说,开发 Green Tea 是为了应对现代 CPU 硬件带来的挑战,随着硬件的发展,这可能会使代码变慢而不是变快。特别是,较新的 CPU 引入了非统一的内存访问,其中一部分核心对一部分内存有特权访问;由于更多的核心竞争内存访问,每个 CPU 的内存带宽减少;以及不断增加的核数,使得 GC 算法更难并行工作。
另一方面,高级 CPU 特性(如向量指令和宽寄存器)提供了显著加速的机会,前提是 GC 算法可以利用它们,kyszek 和 Clements 说。
向量硬件长期以来一直支持在整个向量寄存器上的基本位操作,但从 AMD Zen 4 和 Intel Ice Lake 开始,它还支持一个新的位向量“瑞士军刀”指令,使 Green Tea 扫描过程的关键步骤可以在几个 CPU 周期内完成。总之,这些可以让我们加速 Green Tea 的扫描循环。
如前所述,根据内存工作负载的不同,Green Tea 可以减少 10-40%的垃圾收集开销。对于在垃圾收集器中花费 10%时间的应用程序,这意味着总体 CPU 减少了 1-4%。
然而,并不是所有的工作负载都能从 Green Tea 中受益:
“Green Tea”基于这样的假设,即我们可以在一个页上累积足够的对象进行一次扫描,以抵消积累过程的成本。[…但是有一些工作负载通常要求我们每次只扫描一个对象。这可能比图泛洪更糟糕。
以版本控制 SQL 数据库 dolt 的制造商 dolthub 为例,在生产构建中选择不采用Green Tea:
对于 Dolt 来说,Green Tea 收集器对实际性能数字没有任何影响。实际上,在标记时间上似乎有一个小的回归,但这在我们的延迟基准测试中是无法测量的。
其他早期采用者报告说,Tea Green 在其内存繁重的应用程序中运行 GC 的频率较低,但每个周期消耗更多的 CPU。虽然这减少了 GC 的总体 CPU 消耗,但它显著地增加了延迟。然而,这个行为已经在即将到来的Go 1.26中修复了。
结果的这种可变性是默认情况下不启用新的垃圾收集器的主要原因,尽管根据 Go 团队的说法,它已经可以用于生产环境了。要使用 Go 1.25 测试 Tea Green,可以在构建时通过设置 GOEXPERIMENT=greenteagc 来启用它。
原文链接:








评论