Go Green Tea Gc

介绍

Go Green Tea GC 改变不大,首先要了解一下 Go 以前是怎么处理垃圾回收的。

简单来说,传统 GC 的流程是:从 root 扫描开始,把发现的引用对象加入队列(标记为灰色),然后从队列中取出一个对象,继续扫描它的引用,如果引用对象还没被标记,就再次入队(标记为灰色),直到队列为空。最后把没有被标记的对象(白色)清除掉。

这个过程有一个根本性的问题——引用的对象散落在堆内存的各个角落,CPU 在处理队列中的对象时需要不断跳转访问不同内存地址,缓存命中率极低。事实上,超过 35% 的 CPU 周期都浪费在等待内存访问上,GC 效率因此大打折扣。

Green Tea 是怎么做的?

Green Tea 的做法是把扫描到引用的对象不加入队列,加入队列的是对象所在的 span,span 中维护两个 bitmap 来标记 span 中哪些对象的状态。

  • Seen 位 :记录对象是否已被 GC 标记为可达。Seen = 可达标记位,防止同一个对象被重复入队。
  • Scanned 位:记录对象的内部指针是否已经被遍历过。Scanned = 内部指针扫描状态,防止重复遍历对象内字段。

两个位的配合:

SeenScanned状态描述操作
00新对象,没看过,没扫描标记 Seen=1,入队扫描对象内指针
10已知可达,但指针还没扫描扫描指针,标记 Scanned=1
11已可达且指针扫描过跳过,不用再扫描

这样就能实现三色标记的“灰色→黑色”逻辑:

  • 灰色:Seen=1, Scanned=0 → 可达但指针还没扫描
  • 黑色:Seen=1, Scanned=1 → 可达且指针扫描完毕
  • 白色:Seen=0 → 不可达或未标记

因为按 span 扫描上边的对象,所以 CPU 跳转更友好。

为什么会变快

  1. 减少队列操作频率 - 以 span 为粒度入队,远比以对象为粒度入队的频率低得多,在大量小对象的场景下尤为明显。入队/出队的调度开销因此大幅降低。
  2. 降低多核竞争 - 当 CPU 核心数越多时,原有方案中多个 goroutine 争抢队列的竞争越激烈。span 粒度的队列压力更小,调度器负载更轻,并发扩展性更好。
  3. 提升 CPU 缓存命中率 - span 内的对象在内存中是连续排列的,扫描时具有极强的空间局部性(Spatial Locality)。CPU 缓存行(Cache Line)可以一次加载多个相邻对象的数据,减少主存访问等待。传统 GC 在不同内存区域间随机跳跃,缓存几乎完全失效。
  4. 友好的 NUMA 架构适配 - 在 NUMA(非均匀内存访问)架构下,span 内的对象通常归属同一内存节点,访问延迟远低于跨节点访问。而传统的对象级跳跃访问极易触发跨节点内存读取,开销显著增大。
  5. 解锁硬件向量加速(SIMD)

AVX-512

Go 的 Green Tea GC 在扫描对象指针时,充分利用了 AVX-512 等现代 CPU 向量指令集的能力。传统 GC 往往是逐对象、逐字段地处理指针,这种逐步处理方式无法发挥 SIMD(单指令多数据)并行处理的优势。而在 Green Tea 中:

  • Span 内连续对象 的指针信息被整理成紧凑的 bitmap 或数组。
  • 扫描器可以一次性加载多个对象的指针信息到 SIMD 寄存器中。
  • 同一条指令即可对多条指针进行标记检查、更新 Seen/Scanned 位,极大提高了指针遍历吞吐量。

这意味着在内存访问和 CPU 指令层面都能获得 批量处理 的加速效果,尤其在 span 中包含大量小对象的情况下性能提升明显。

并发与增量回收

Green Tea 仍然保持 Go GC 的 并发回收增量标记 特性:

  1. 并发标记

    • 多个 goroutine 扫描 span 内对象 bitmap,每个核心处理不同 span,减少全局队列竞争。
    • Seen/Scanned 位保证即使多个 goroutine 扫描同一 span,也不会重复扫描对象内指针。
  2. 增量标记

    • GC 标记阶段可以与应用程序 goroutine 并行执行,避免 STW(Stop-The-World)时间过长。
    • 由于 span 内对象紧凑连续,增量标记的每次批量扫描都更高效,缓存命中率更稳定。

总结

Green Tea GC 的核心优化思路可以概括为:

  • 队列粒度优化:对象级 → span 级,减少入队/出队开销。
  • 位图标记:Seen/Scanned 双 bitmap,实现三色标记逻辑,避免重复扫描。
  • 内存局部性优化:连续对象内存排列,提高 CPU 缓存命中率。
  • 硬件加速:利用 AVX-512 等 SIMD 指令批量扫描对象指针。
  • 并发友好:多核扩展性强,NUMA 架构适配良好。

Table of Contents

输入 2 个或更多字符开始搜索