giftiaのblog

go GC 三色标记

· giftia

三色标记法

  • 白色:尚未被追踪。
  • 灰色:已被追踪,但其子节点还未被探索。
  • 黑色:已被完全探索;在本轮 GC 中不会再扫描其子节点。

img img img img img

强三色不变式

不存在黑色对象引用白色对象。

弱三色不变式

黑色对象可以引用白色对象,但每个这样的白色对象都必须仍然可从某个灰色对象到达(即存在灰色对象作为它的上游路径)。

强、弱三色不变式用于避免并发标记期间的漏标,保证仍然可达的对象不会被错误回收。

写屏障

写屏障(write barrier)是在 GC 并发标记期间拦截指针修改的机制,使对象图发生变化时仍能满足三色不变式。

  1. 插入写屏障: 并发标记阶段,当黑色对象新增指向白色对象的指针时,将被指向对象着灰(加入待扫描队列)。

  2. 删除写屏障: 并发标记阶段,当对象删除一个指向白色对象的指针时,将原来被指向的对象着灰,避免它因原引用消失而漏标。

  3. 混合写屏障: 结合插入和删除两类屏障。Go 的并发 GC 使用 Yuasa 删除屏障和 Dijkstra 插入屏障:写入前将旧指针指向的对象着灰;当当前 goroutine 的栈仍为灰色时,也将新指针指向的对象着灰。

注意

  • 栈区没有写屏障
  • 对当前栈帧的直接写入通常不生成写屏障;但通过可能指向堆的指针写入栈时,编译器仍可能生成写屏障。GC 会扫描各 goroutine 的栈,不能将栈中新引用简单理解为“直接标记为黑色”,也不会因为省略部分栈写屏障就必然等到下一次 GC。

参考:https://www.bilibili.com/video/BV1SLtVe7EDR?vd_source=1fc15dfc7872eca10bc43b8ee8d73958