Golang的GC发展史

Go V1.3之前的标记-清除:

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

标记-清除的缺点:

STW(stop the world):让程序暂停,程序出现卡顿

标记需要扫描整个heap,同时清除数据会产生heap碎片

为了减少STW的时间,后来对上述的第三步和第四步进行了替换。

Go V1.5 三色标记法:

  1. 把新创建的对象默认标记为白色
  2. 每次GC回收开始,然后从根节点开始遍历所有对象,把遍历到的对象从白色集合放入灰色集合
  3. 遍历灰色集合,将灰色对象引用的对象从白色集合放入到灰色集合,之后将此灰色对象放入到黑色集合
  4. 重复第三步,直到灰色中无任何对象
  5. 回收所有的白色标记的对象,也就是回收垃圾

三色标记法在不采用STW保护时会出现:

  1. 一个白色对象被黑色对象引用
  2. 灰色对象与它之间的可达关系的白色对象遭到破坏

这两种情况同时满足,会出现对象丢失

解决方案:

  1. 强三色不变式:强制性的不允许黑色对象引用白色对象(破坏1)
  2. 弱三色不变式:黑色对象可以引用白色对象,白色对象存在其他灰色对象对它的引用,或者可达它的链路上游存在灰色对象(破坏2)

屏障:

  1. 插入屏障:在A对象引用B对象的时候,B对象被标记为灰色(满足强三色不变式,黑色引用的白色对象会被强制转坏为灰色)。

只有堆上的对象触发插入屏障,栈上的对象不触发插入屏障。在准备回收白色前,重新遍历扫描一次栈空间。此时加STW暂停保护栈,防止外界干扰.

不足:结束时需要使用STW来重新扫描栈

  1. 删除屏障:被删除的对象,如果自身为灰色或者白色,那么被标记为灰色(满足弱三色不变式)。

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

Go V1.8的三色标记法+混合写屏障机制:

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

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

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

请我喝杯咖啡吧~

支付宝
微信