Golang 三色标记 + GC混合写屏障机制

Go v1.3之前的标记清除

流程

  1. 暂停程序业务逻辑, 找出 可达的对象,和可达对象。
  2. 开始标记,程序找出它所有可达的对象,并做上标记。
  3. 标记完 之后,然后开始清除未标记的对象.
  4. 停止暂停,让程序继续跑。然后循环重复这个过程,直到process程序 命周期结束。

缺点

  1. STW,stop the world;让程序暂停,程序出现卡顿 (重要问题)。
  2. 标记需要扫描整个heap
  3. 清除数据会产生heap碎片
  4. 将第四步和第三步换位置,缩短STW的范围

Go v1.5三色标记法

流程

  1. 只要是新创建的对象,默认的颜 都是标记为“白色”

  2. 每次GC回收开始, 然后从根节点开始遍历所有对象,把遍历到的对象从白色集合放 “灰 ”集合。

  3. 遍历灰色集合,将灰色对象引入的对象从白色集合放入灰色集合,之后将此灰色对象放入黑色集合

  4. 重复第三步, 直到灰色中无任何对象.

  5. 回收所有的白色标记表的对象. 也就是回收垃圾.

只使用三色标记法

  1. 一个白色对象被黑色对象引用(黑色对象之后的不会再去判断)
  2. 灰色对象与它之间的可达关系的白色对象遭到破坏

两个条件同时满足,那么会出现对象丢失的现象

强弱三色不变式

  1. 强三色不变式:强制性的不允许黑色对象引用白色对象
  2. 弱三色不变式:黑色对象可以引用白色对象,白色对象存在其他灰色对象对它的引用,或者可达它的链路上游存在灰色对象
  3. 如果三色标记满足强弱不变式之一,即可保证不丢失对象

屏障机制

插入屏障

对象被引用时触发的机制

  1. 具体操作: 在A对象引用B对象的时候,B对象被标记为灰 。(将B挂在A下游,B必须被标记为灰 )
  2. 满 : 强三色不变式. (不存在黑色对象引用白色对象的情况 , 因为白色会强制变成灰 )

不足:结束时需要STW来重新扫描栈, 约需要10~100ms

删除屏障

对象被删除时触发的机制

  1. 具体操作: 被删除的对象,如果自身为灰色或者白色 ,那么被标记为灰 。
  2. 满 : 弱三色不变式. (保护灰色对象到白色对象的路径不会断)

不足:

  1. 回收精度低,一个对象即使被删除 最后 个指向它的指针也依旧可以活过这一轮, 在下一轮GC中被清理掉。

Go v1.8混合写屏障机制

具体操作

  1. GC开始将栈上的对象全部扫描并标记为黑色(之后不再进行第二次重复扫描, 需STW)
  2. GC期间,任何在栈上创建的新对象,均为黑色。
  3. 被删除的对象标记为灰色。
  4. 被添加的对象标记为灰色。

满足:变形的弱三色不变式. (结合了插入、删除写屏障两者的优点)

总结:

  1. Go V1.3 普通的标记清除法, 整体过程需要STW,效率极低
  2. Go V1.5 三色标记法, 对空间启动写屏障,栈空间 启动, 全部扫描之后,需要重新扫描 次栈(需要STW), 效率普通
  3. Go V1.8 三色标记法,混合写屏障机制, 栈空间不启动,堆空间启动, 整体过程几乎不需要STW, 效率较 高