golang 垃圾清除算法

264 阅读3分钟

先说结论,留个印象

  • GoV1.3- 普通标记清除法,整体过程需要启动STW,效率极低。

  • GoV1.5- 三色标记法, 堆空间启动写屏障,栈空间不启动,全部扫描之后,需要重新扫描一次栈(需要STW),效率普通

  • GoV1.8-三色标记法,混合写屏障机制, 栈空间不启动,堆空间启动。整个过程几乎不需要STW,效率较高。

Go V1.3之前的标记-清除(mark and sweep)算法

  • 标记(Mark phase)
  • 清除(Sweep phase)

整个过程直接暂停业务,标记

2 标记-清除(mark and sweep)的缺点

  • STW,stop the world;让程序暂停,程序出现卡顿 (重要问题)
  • 标记需要扫描整个heap;
  • 清除数据会产生heap碎片、

三、Go V1.5的三色并发标记法

Golang中的垃圾回收主要应用三色标记法,GC过程和其他用户goroutine可并发运行,但需要一定时间的STW(stop the world) ,所谓三色标记法实际上就是通过三个阶段的标记来确定清楚的对象都有哪些?我们来看一下具体的过程。

第一步 , 每次新创建的对象,默认的颜色都是标记为“白色

图片.png 第二步, 每次GC回收开始, 会从根节点开始遍历所有对象,把遍历到的对象从白色集合放入“灰色”集合如图所示。

图片.png 第三步, 遍历灰色集合,将灰色对象引用的对象从白色集合放入灰色集合,之后将此灰色对象放入黑色集合,如图所示。

图片.png 第四步, 重复第三步, 直到灰色中无任何对象,如图所示。

图片.png

图片.png 图片.png 第五步: 回收所有的白色标记表的对象. 也就是回收垃圾,如图所示。

如果三色标记没有stw

图片.png 可以看出,有两种情况,在三色标记法中,是不希望被发生的。

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

  • 条件2: 灰色对象与它之间的可达关系的白色对象遭到破坏 (灰色同时丢了该白色) 如果当以上两个条件同时满足时,就会出现对象丢失现象!

    屏障机制

  • 强三色不变式(插入屏障)(只对堆内存有效

堆进行插入屏障,但是栈不能,所以在堆完成后,要对栈进行三色标记,要stw

被引用的白色要变成黑色。 所以不存在黑色对象引用到白色对象的指针。

  • 弱三色不变式(删除屏障)、

被删除的对象,如果自身为灰色或者白色,那么被标记为灰色。

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

弱三色不变色实际上是强制性的不允许黑色对象引用白色对象,这样就不会出现有白色对象被误删的情况。

Go V1.8的混合写屏障(hybrid write barrier)机制

混合写屏障规则

具体操作:

1、GC开始将栈上的对象全部扫描并标记为黑色(之后不再进行第二次重复扫描,无需STW),

2、GC期间,任何在栈上创建的新对象,均为黑色。

3、被删除的对象标记为灰色。

4、被添加的对象标记为灰色。

满足: 变形的弱三色不变式.

Golang中的混合写屏障满足弱三色不变式,结合了删除写屏障和插入写屏障的优点,只需要在开始时并发扫描各个goroutine的栈,使其变黑并一直保持,这个过程不需要STW,而标记结束后,因为栈在扫描后始终是黑色的,也无需再进行re-scan操作了,减少了STW的时间