一句话定义
三色标记算法是一种 并发垃圾回收 策略,通过将对象分为三种颜色(黑、灰、白)来追踪对象的引用关系,从而实现一边运行程序一边回收内存。
核心工作流程
该算法将对象分为三色,本质是建立一个 “待处理队列”:
- 白色:潜在垃圾。标记结束仍为白色则回收。
- 灰色:活跃对象,但其引用的子对象尚未扫描。
- 黑色:活跃对象,且其引用的子对象已全部扫描。
标记步骤
- 初始状态:所有对象标记为 白色。
- 根扫描 (Root Scan):在 STW 1 (Mark Setup) 阶段,从根对象(全局变量、栈变量)出发,将直接引用的对象标为 灰色。
- 迭代扫描:从灰色集合取出一个对象标为 黑色,并将其引用的所有子对象标为 灰色,直到灰色集合为空。
- 清理回收:回收所有白色对象。
为什么需要“灰色”?灰色是并发标记的 中间缓冲区。它确保了 GC 可以分步进行,而不会因为对象状态的瞬间改变而丢失追踪路径。
解决并发问题的关键:写屏障
为了防止并发修改导致活跃对象被误删,只要满足以下 任意一种 不变性,就能保证标记的正确性:
- 强三色不变性:不允许黑色引用白色(源头切断)。
- 弱三色不变性:黑色可引用白色,但该白色必须有灰色对象保护(路径可达)。
知识扩展
- STW (Stop The World):三色标记虽然是并发的,但在开启和关闭写屏障时仍需短暂暂停程序。
- 根对象 (Root Set):包括全局变量、Goroutine 栈上的指针、寄存器中的指针等。
- 内存碎片:标记清除算法本身不移动对象,可能产生内存碎片,Go 通过分级分配(mspan)来缓解此问题。