Go垃圾回收
WsWHL Lv3

1. 常见垃圾回收算法对比

垃圾回收(Garbage Collection, GC)是指对程序中不再使用的内存资源进行自动回收的操作。常见的 GC 算法包括:

  • 引用计数(Reference Counting)

    • 原理:每个对象维护一个引用计数器,增加引用时 $+1$,引用失效时 $-1$,计数归零时直接回收。
    • 优点:回收及时,不会出现内存耗尽或达到阈值才触发的情况。
    • 缺点:无法解决循环引用问题,且频繁更新计数有性能开销。
  • 标记-清除(Mark-Sweep)

    • 原理:从根对象(GC Roots)开始遍历所有可达对象并标记“被引用”,遍历结束后对未标记的白色对象进行回收。
    • 优点:能够有效解决循环引用问题。
    • 缺点:需要 Stop The World(STW),短暂停顿所有用户协程/线程。
  • 分代收集(Generational Collection)

    • 原理:根据对象的生命周期长短划分为新生代和老年代,不同代采用不同的回收算法和频率。
    • 优点:针对不同生命周期的对象优化,整体回收性能优秀。
    • 缺点:实现逻辑较为复杂。

2. 三色标记法(Three-color Marking)

Go 语言采用了并发三色标记清除算法。算法将对象分为三种颜色:

  1. 白色:未被扫描到的对象(潜在的垃圾对象)。
  2. 灰色:已被扫描到,但其引用的其他对象尚未被完整扫描。
  3. 黑色:已被扫描到,且其引用的所有对象也都已被扫描(可达的安全对象)。

标记过程:

  1. 初始状态:所有对象归为白色
  2. 根扫描:从根节点(如全局变量、栈上的变量)开始遍历,将直接可达的对象放入灰色集合。
  3. 对象追踪:遍历灰色集合,将灰色对象引用的对象标记为灰色,然后将该灰色对象自身转为黑色
  4. 循环迭代:重复上述步骤,直到灰色集合中没有对象。
  5. 垃圾清理:此时剩下的白色对象即为不可达垃圾,进行统一回收。

3. STW 与写屏障(Write Barrier)

3.1 为什么需要 STW?

为了防止在 GC 扫描过程中,用户协程修改指针引用关系,导致 GC 误删正在被引用的存活对象。通过 Stop The World (STW) 暂时挂起所有正在运行的 Goroutine,可以保证引用数据的一致性。目前 Go 的 STW 优化已能控制在 1ms 以下

3.2 对象丢失的两个必要条件

若要完全消除或极大地缩短 STW,引入混合写屏障来解决并发标记期间的引用变更问题。对象被误回收必须同时满足以下条件:

  1. 黑色对象新增了指向白色对象的引用。
  2. 该白色对象没有其他灰色对象的直接/间接引用,或者原有的灰色引用被删除了。

3.3 屏障技术实现

屏障技术通过破坏上述两个条件之一来保证三色不变性:

  • Dijkstra 插入写屏障(强三色不变性)
    • 规则:黑色节点不允许直接引用白色节点。当黑色节点新增白色节点的引用时,强制将该白色节点修改为灰色。
  • Yuasa 删除写屏障(弱三色不变性)
    • 规则:允许黑色节点引用白色节点,但前提是该白色节点仍有其他灰色节点的间接引用。当白色节点被删除引用时,悲观地将其置为灰色,防止误杀。
 评论