GolangGC之三色标记

Golang Garbage Collector

Go 1.3 mark and sweep方法

步骤:

  • 第一步暂停程序业务逻辑,找出所有对象,找出不可达对象,和可达对象
  • 第二步开始标记,程序找出它所有可达的对象,并做上标记
  • 标记完成,清除未标记的对象
  • 停止STW

业界常见的垃圾回收算法有以下几种:

  • 引用计数:对每个对象维护一个引用计数,当引用该对象的对象被销毁时,引用计数减1,当引用计数器为0时回收该对象。
    • 优点:对象可以很快地被回收,不会出现内存耗尽或达到某个阀值时才回收。
    • 缺点:不能很好地处理循环引用,而且实时维护引用计数,也有一定的代价。
    • 代表语言:Python、PHP、Swift
  • 标记-清除:从根变量开始遍历所有引用的对象,引用的对象标记为”被引用”,没有被标记的进行回收。
    • 优点:解决了引用计数的缺点。
    • 缺点:需要STW,即要暂时停掉程序运行。标记需要扫描整个heap。清除数据会产生heap碎片
    • 代表语言:Golang(其采用三色标记法)
  • 分代收集:按照对象生命周期长短划分不同的代空间,生命周期长的放入老年代,而短的放入新生代,不同代有不同的回收算法和回收频率。
    • 优点:回收性能好
    • 缺点:算法复杂
    • 代表语言: JAVA

Go1.5 三色标记法

维护三个集合。

白色:所有对象起初全标记为白色,表明还没有遍历到的。

image-20210330205329094

GC开始需要做初始化灰色结点,即需要从定义的ROOT集合遍历找到对应的白色结点,将对应的白色结点转为灰色结点。

灰色:遍历第一次得到灰色对象。

黑色:遍历灰色结点,灰色结点如果仍能找到对象可达则标记为黑色,而下一个节点则标记为灰色。

重复第一步,直到灰色表中没有任何对象。

收集白色对象(垃圾, 没有再被任何使用到)

三色标记无STW的问题

三色标记STW性能比较低。

image-20210330211114082

存在的问题:灰色对象2引用的对象3,可能被用户程序修改,而同时被标记位黑色的对象4又引用了该对象3,因为黑色对象已经不会被扫描,灰色对象2已经不再引用对象3,对象不能被标记为灰色,故最后被GC掉,但是对象4存在引用关系,就会发生错误。

image-20210330211650073

强弱三色不变式

强三色不变式 -- 破坏条件1

强制性的不允许黑色对象引用白色对象。

黑色可以引用灰色对象,但是不允许引用白色对象。

弱三色不变式 -- 破坏条件2

黑色可以引用白色对象,白色对象存在其他灰色对象对它的引用(存在另外一条路可达)。

image-20210330212034683

满足强弱之一,即可保证对象不丢失

插入写屏障 -- 对象被引用的时候 触发的机制

A对象引用B对象,B对象被标记为灰色对象。(如果现在是黑色引用白色 就会强制把白色变为黑色 强三色不变式

image-20210330212726470

栈不启用插入屏障,堆启用插入屏障

在准备回收白色之前,需要重新扫描一遍栈空间,加入STW暂停保护栈,防止外界干扰

这样相当于2遍扫描栈 如果没有第一次 会发生什么?

删除屏障 -- 对象被删除的时候 触发的机制

被删除的对象,如果自身为灰色或者白色,那么被标记为灰色(弱三色不变式 保护灰色对象到白色对象的路径不会断)

image-20210330214154434

回收精度比较低,每次都可以活过一轮,在下一轮GC中被回收

Go 1.8 三色标记 + 混合写

image-20210331175410792

具体操作:

  • GC开始将栈上的对象全部扫描并标记为黑色(不需要重复扫描以及STW)
  • GC期间,任何在栈上创建的对象,均为黑色
  • 被删除的对象标记为灰色
  • 被添加的对象标记为灰色

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

image-20210331180102322

1 满足弱三色

2 满足强三色

image-20210331180144130

混合写屏障场景1:对象被一个堆对象删除引用,成为栈对象的下游

image-20210331180746205

image-20210331181210460

image-20210331181146879

混合场景二:对象被一个栈对象删除引用,成为另外一个栈对象的下游

image-20210401150601248

image-20210401150752332

混合场景三:对象被一个堆对象删除引用,成为另外一个堆对象的下游

image-20210401150944096

对象10引用对象7的时候就会将对象7标记为灰色

image-20210401151141377

混合场景四:对象被一个堆对象删除引用,成为另外一个栈对象的下游

image-20210401151318835

总结

原文地址:https://www.cnblogs.com/DengSchoo/p/14608066.html