5、Golang三色标记混合写屏障GC模式全分析 (yuque.com)
第1讲-课程目标_哔哩哔哩_bilibili
Golang三色标记+GC混合写屏障
Go V1.3之前的标记清除(mark and sweep)
垃圾回收、内存管理、自动适放、三色标记法、STW (stop the world)
图的遍历?可达性分析
此时第一步为STW暂停(让大家都先别干活了)将1-2-3 4-7等五个可达对象坐上标记,此时没有被标记的对象说明程序是不需要它的
不可达的就会被删除。
标记清除法的缺点
1:让程序暂停,程序出现卡顿(重要问题,影响业务)
2:标记需要扫描整个heap,时间复杂度高
3:清除数据辉产生heap碎片
Go V1.5三色标记法(白灰黑)
尝试采用新的标记模式来替代清除标记法
1、程序起初创建,全部标记为白色,将所有对象放到被色集合
2、遍历Root Set(非递归遍历只遍历一次),得到灰色节点
遍历灰色标记表,将可达的对象从白色标记为灰色,遍历之后的灰色,标记为黑色
之后再重复上一步,直到灰色标记表中无任何对象
在之后就收集所有白色对象(垃圾)
其本质就是利用队列进行bfs算法,标记所有可达对象
三色标记法中无STW问题?
如果三色标记法中不启动stw情况
然后与此同时,对象2将指向对象3的指针p移除,对象3就被挂在了已经扫描完成的黑色的对象4下,但对象4此时已经在黑色标记表中了
此时的对象3有可能会被垃圾回收掉
所以三色标记法最不希望被发生的事:白色对象被黑色对象引用。条件二:灰色对象丢失那个白色对象的可达关系
两个条件同时满足时,就会出现对象丢失现象!
所以想避免最简单的方式就是STW,STW过程有明显的资源浪费,对所有用户程序都有很大影响。
如何能在保证对象不丢失的情况尽可能的提高GC效率,减少STW时间呢?
但是不用stw所以就避免两个条件同时满足,破坏他们同时成立
1、强三色不变式
强制性的不允许黑色对象引用白色对象
2、弱三色不变式
黑色对象可以引用白色对象,但是前提是白色对象存在其他灰色对象对它的引用,或则可达它的链路上游存在灰色对象
在三色标记中如果满足强/弱之一,即可保证对象不丢失
插入写屏障和删除写屏障
在程序的执行过程中,额外的添加一条判断机制 例如:Hook、回调、handler
插入屏障:对象被引用时 触发的机制
删除屏障:对象被删除的时候 触发的机制
插入屏障
堆中触发插入屏障
循环操作后直到没有灰色标记后,在准备回收白色前,重新扫描一下栈空间。此时加STW暂停保护栈,防止外界干扰(有新的白色被黑色添加)
之后再进行清除
插入屏障的不足:结束时需要STW来重新扫描栈,大约需要10~100ms
删除屏障
这样有可能会出现当对象1删除对象5的时候,把5转换成灰色,有可能会出现,5-2-3本来应该被删除的却变为了黑色对象,所以5-2-3会多活过一轮,在下一轮GC中会被清理掉
回收精度低,一个对象即使被删除了最后一个值向它的指针也依旧可以活过这一轮,在下一轮GC中被清理掉
Go V1.8基于三色标记法的混合写屏障机制
满足:变形的若三色不变式。(结合了插入、删除写屏障两者的优点)
可以达到被移走的对象是被灰色保护的。(弱三色) 和新加入的下游对象标记灰色(强三色)
注意:1是将栈上所有可达对象标为黑色 (它的特点是GC开始的时候优先扫描栈 )栈为了添加效率是不启用屏障的,堆会启用屏障
总结
GoV1.3- 普通标记清除法,整体过程需要启动STW,效率极低。
GoV1.5- 三色标记法, 堆空间启动写屏障,栈空间不启动,全部扫描之后,需要重新扫描一次栈(需要STW),效率普通
GoV1.8-三色标记法,混合写屏障机制, 栈空间不启动,堆空间启动。整个过程几乎不需要STW,效率较高。