1.Go垃圾回收
go1.3之前使用标记清除算法
go1.5使用三色标记清除法和插入写屏障机制
go1.8结合删除写屏障机制,使用混合写屏障法
root对象:
根对象是指程序不需要通过其他对象就可以直接访问到的对象。如全局变量,执行栈。
1.1 标记清除法
普通标记清除法,整体过程需要启动STW,效率极低。
步骤
1.暂停程序业务逻辑,分类出可达和不可达的对象
2.标记所有可达对象
3.清除未标记的对象
4.结束暂停,继续执行程序。然后循环重复这个过程,直到程序生命周期结束
缺点:
1.让程序暂停
2.标记需要扫描整个heap
3.清除数据会产生heap碎片
1.2 三色标记清除法
三色标记法, 堆空间启动写屏障,栈空间不启动,全部扫描之后,需要重新扫描一次栈(需要STW),效率普通
1.2.1 步骤
1.初始时,所有对象被标记为白色
2.遍历rootset,将直接可达的对象标记为灰色
3.遍历灰色对象,将直接可达对象标记为灰色,自身标记为黑色
4.重复第3步,直到标记完所有可达对象
5.将标记为白色的对象当做垃圾回收掉
1.2.2 上述步骤的问题
上述三色标记法需要依赖STW(暂停程序),如果不暂停程序,程序的逻辑 改变对象引用关系,这种动作如果在标记阶段做了修改,会影响标记结果的正确性。
例子
1.对象1可达 对象2,4;对象6可达对象7。
2.对象2删除了对象3的引用,对象6创建指针指向对象3
3.由于对象6不会再进行扫描,对象3一直会是白色标记,最后被当作垃圾回收掉
导致上文例子的情况,需要满足下面两个条件:
1.白色对象被黑色对象引用
2.灰色对象与白色对象之间的可达关系被破坏
1.2.3 两种不变式
解决1.2.2中的两个条件
- 强三色不变式
不允许黑色对象引用白色对象
- 弱三色不变式
黑色对象可以引用白色对象,但白色对象的上游必须存在灰色对象
1.2.4 屏障机制
为了遵循两种不变式,提出了两种实现机制
- 插入写屏障
规则:当一个对象引用另一个对象时,将另一个对象标记为灰色
需要注意的是:
插入写屏障仅会在堆内存中生效,不对栈内存生效。因为go在并发运行时,大部分操作都发生在栈上,函数调用非常频繁。在栈上进行屏障保护会有性能问题。
1.2.4.1 插入写屏障执行过程
1.对象2标记为灰色,对象2引用对象3
2.对象6创建一个指针,指向对象3。外界向对象1添加对象4。插入写屏障保证一个对象引用另一个对象时,另一个对象标记为灰色。但由于插入写屏障不作用于栈内存。所以对象3变为灰色,对象4为白色。
3.对象2删除对象3的引用
4.继续执行三色标记过程,结果如上图。
由于栈上的对象没有插入写屏蔽,在三色标记完成后,仍然可能存在栈上的白色对象被黑色对象引用(如对象4)。所以最后需要对栈上的空间进行STW,防止对象被误删除。
5.对栈空间执行STW
6.对栈空间重新进行扫描,将对象4标记为黑色,最后垃圾回收白色标记的对象5和8,符合预期
- 删除写屏障
规则:在删除引用时,如果被删除引用的对象自身为灰色或白色,那么被标记为灰色。
需要注意的是:
一个对象的引用被删除后,即使没有其他存活的对象引用它,它仍然会活到下一次GC执行。相当于本次GC有一些应该清除的对象没有清除,会产生很多的冗余扫描成本,降低了GC的精度。
1.2.4.2 删除写屏障执行过程
1.GC开始时使用STW扫描堆栈来记录初始快照。对象2标记为灰色,对象2引用了对象3
2.被标记为黑色的对象6引用了对象3
3.灰色对象2去掉了对 对象3的引用,触发了删除写屏障(被删除引用的对象如果是白色或灰色,置为灰色),将对象3标记为灰色
4.遍历完所有可达对象,回收白色对象5,8,符合预期
1.2.4.3 两种屏蔽机制的总结
插入写屏障:
插入写屏障不能作用于栈内存,所以最后需要给栈空间进行STW,然后rescan保证引用的白色对象存活。
删除写屏障:
在GC开始时,会扫描记录整个栈做快照,从而在删除操作时,可以拦截操作,将白色对象置为灰色对象。
回收精度低。
1.3 混合写屏障
三色标记法,混合写屏障机制, 栈空间不启动,堆空间启动。整个过程几乎不需要STW,效率较高。
1.3.1 机制
1.GC刚开始时,将栈上所有可达对象标记为黑色
2.GC期间,任何在栈上新创建的对象,均为黑色。
3.堆上被删除引用的对象标记为灰色
4.堆上新添加的对象标记为灰色
1.3.2 步骤
1.初始时,所有对象被标记为白色
2.GC开始时,将栈上所有可达对象标记为黑色
3.开始三色标记,将对象6标记为灰色。同时栈上对象3新引用了对象9,触发混合屏蔽机制(GC期间,任何在栈上新创建的对象,标记为黑色),将对象9标记为黑色。
4.在堆上创建对象10,对象6新引用了对象10,触发混合屏障机制(堆上新添加的对象标记为灰色),将对象10标记为灰色
5.对象1引用了对象7,由于对象1在栈上,不会触发混合屏障机制,仅仅只是挂载
6.对象6删除了对象7的引用,对象6在堆上,触发混合屏障机制(堆上被删除引用的对象,标记为灰色),将对象7标记为灰色
7.将所有可达对象标记完成后,GC结束,最后将对象5,8回收