关于GC

即垃圾回收机制,对于高级编程语言来说比较重要,尤其是业务性比较强的语言,比如python,java,可以让程序员更加关注业务而非内存管理本身,降低开发成本。

Go V1.3的标记清除法

流程

如图,首先是程序与对象之间的可达关系,可以看出目前的可达对象有1-2-3,4-7等五个对象,当触发GC机制的时候,会先进行STW操作进行暂停,之后对1-23,4-7等五个对象打上标记。而没有标记的对象没有被程序需要,就是垃圾会被回收。接下来STW结束,继续跑。

缺点

  • 需要进行STW操作,让程序暂停,程序会出现卡顿(重要问题)
  • 标记需要扫描整个heap
  • 清楚数据会产生heap碎片

改进

早期的go语言尝试了减小STW的暂停范围来减少STW所需要的时间。

通常在STW之后,要经过启动STW->标记->清除->停止STW的流程,而清除事实上可以放到停止STW之后再进行,另开一个线程进行清除操作。

但是这样还是无法满足需要,所以采用了新的方法来代替标记清除法。

Go V1.5三色标记法

流程

第一步,首先只要是新创建的对象,默认的颜色就是被标记为白色。

第二步,每次的GC回收开始,然后从根节点开始遍历所有对象,把遍历到的对象从白色集合放入灰色结合

第三步,遍历所有的灰色集合,把灰色对象引用的对象从白色集合放入到灰色集合之中,之后把这个灰色对象放入到黑色集合之中。

第四步,重复第三步,直到灰色之中无任何对象,整个节点只有白色和黑色节点。

第五步,回收白色的垃圾节点。

无STW时出现的问题

  • 一个白色对象被黑色对象引用(白色被挂在黑色下)

  • 灰色对象与它之间的可达关系的白色对象遭到破坏(灰色同时丢失了该白色)

同时满足这两个条件的时候,就会出现对象丢失的现象。

比如在这张图里面,当对象4(黑色)引用了对象3,而对象2恰好对对象3取消引用的时候,对象3就不会被遍历,导致被回收清除。

三色不变式

为了破坏三色标记法的两个条件,出现了三色不变式这一机制。

强三色不变式

破坏条件1,强制性的不允许黑色对象引用白色对象

弱三色不变式

破坏条件2

屏障机制

插入屏障

当对象被引用时,触发机制,具体操作为:在A对象引用B对象的时候,B对象被标记为灰色。(把B挂在A下游,B必须被标记为灰色)这样满足强三色不变式,因为不会存在黑色对象引用白色对象的情况了,因为白色会强制变成灰色)

但是插入屏障只会针对堆上的对象使用,栈上不会生效。因为栈的空间比较小,对性能要求比较高,如果每次 添加对象都要进行一次插入屏障判断,就会很影响性能。

所以为了保证栈上的空间可以正常完成GC,在准备回收白色之前,需要重新遍历扫描一次栈空间,此时加STW暂停保护栈,防止外界造成的干扰(有新的白色被黑色添加)

删除屏障

对象被删除时触发的机制,具体操作为:被删除的对象,如果自身为灰色或者白色,那么,被标记为灰色。

具体流程为:在开始GC 之前,必须 STW ,对整个根做一次起始快照。当赋值器(业务线程)从灰色或者白色对象中删除白色指针时候,写屏障会捕捉这一行为,将这一行为通知给回收器。

这么做可以满足弱三色不变式,保护灰色对象到白色对象的路径不被断开。

它的不足之处在于回收精度低,一个对象即使被删除了最后一个指向它的指针,仍然可以活过这一轮GC(因为这一轮它被标记为了灰色->黑色),在下一轮GC的时候被删除掉。

此外,删除屏障和插入屏障一样,不适合在栈空间上面进行,因为栈空间难以满足每一次都进行hook操作。

一个疑问

在这个例子中(黑色删除引用,指向一个之前不可达的白色对象),如果按照删除写屏障来不是会出错吗?

Go V1.8混合写屏障

在V1.8之后,使用的是由插入屏障 和删除屏障组成的混合写屏障

内容

  • GC开始,把栈上的全部对象标记为黑色,之后便不再需要重新扫描。
  • GC期间,任何在栈上新创建的对象都标记为黑色
  • 写屏障把被删除的对象标记为灰色
  • 写屏障把新添加的对象标记为灰色

其中,写屏障不在栈上面使用。

一些理解

混合写屏障主要解决了V1.5版本最后需要STW重新扫一边栈空间的问题。

采用的方法是通过1,2条,保证GC期间栈空间一直不出错,不需要最后重新STW一次,那么既然1,2可以避免了4的re-scan,为什么还要加入个3呢

这里想到一个反例说明仍然需要3删除写屏障:

图中的上面三个输入栈空间,在GC开始的时候已经被打黑了,其它的都是堆空间的。

可以看到如果只有1,2,4的话,这里的a就会被误回收。

那么如果只有1,2,3会发生什么事呢?这里可以直接用上面删除写屏障的一个疑问来说明仍然不行。

所以,当同时满足1,2,3,4四条内容的时候,就可以在避免最后的STW re-scan的同时,保证不会发生误删除的现象。