GC 三色标记法

一、三色标记法
三色标记法是 Go 垃圾回收的核心算法,通过颜色标记对象状态,实现增量式垃圾回收:
- 颜色定义:
• 白色:未扫描或已确定为垃圾的对象。
• 灰色:已发现但未完成扫描的对象(中间状态)。
• 黑色:已扫描且确认存活的对象。 - 标记流程:
• 初始标记:所有对象为白色,根对象(全局变量、栈等)标记为灰色。
• 并发标记:从灰色对象递归遍历引用链,标记为黑色。
• 清除:回收所有白色对象。 - 目标:通过增量式标记减少 STW(Stop-The-World)时间,支持并发标记与程序运行。
二、写屏障(Write Barrier)
写屏障是并发标记阶段的关键技术,用于在对象引用关系变化时维护三色不变性,防止误回收:
- 插入写屏障:
• 规则:当黑色对象引用白色对象时,将白色对象标记为灰色。
• 问题:需在标记结束后 STW 重新扫描栈,导致延迟。 - 删除写屏障:
• 规则:删除引用时,若被删对象为白色或灰色,则标记为灰色。
• 问题:回收精度低,需下一轮 GC 处理残留对象。
三、混合写屏障(Hybrid Write Barrier)
Go 1.8 引入混合写屏障,结合插入与删除屏障优势,实现低延迟并发标记:
- 核心规则:
• 堆对象修改:
◦ 新引用的对象(插入操作)标记为灰色。
◦ 旧引用的对象(删除操作)标记为灰色。
• 栈对象处理:
◦ GC 开始时将栈对象全部标记为黑色,后续新对象直接标记为黑色。 - 优势:
• 避免栈重复扫描:栈对象初始标记为黑色,无需 STW 重新扫描。
• 弱三色不变性:允许黑色对象引用白色对象,但需灰色对象间接保护路径。
• 低延迟:全程并发,STW 时间压缩至微秒级。 - 流程示例:
• 新增引用(堆):黑色对象 A → 白色对象 B → B 标记为灰色。
• 删除引用(堆):黑色对象 C 删除引用 D → D 标记为灰色。
四、对比与总结
机制 | 特点 | 适用场景 |
---|---|---|
插入写屏障 | 防止黑色引用白色,需 STW 重扫栈 | 早期 Go 版本(1.5 前) |
删除写屏障 | 保护旧引用,精度低 | 小内存场景(嵌入式系统) |
混合写屏障 | 结合两者,避免栈扫描,低延迟 | Go 1.8+ 默认策略,高并发场景 |
五、工程启示
- 减少堆分配:使用对象池(
sync.Pool
)复用对象,降低 GC 压力。 - 避免指针滥用:值类型优先,减少引用链复杂度。
- 参数调优:通过
GOGC
调整触发阈值,平衡内存与性能。 - 监控指标:结合
pprof
分析堆内存、GC 耗时等关键指标。
通过三色标记法结合混合写屏障,Go 在保证低延迟的同时实现了高效的并发垃圾回收,成为高并发场景下的重要技术优势。