Golang GC 回收机制
1. Go1.3 标记清除 ( mark and sweep )
标记清除法是一种最基本的垃圾回收算法,用于回收不再使用的内存空间。标记清除有两个阶段,标记阶段和清除阶段
1.1 标记阶段
首先,暂停所有业务逻辑 ( STW ),垃圾收集器首先会从根对象(如全局变量、活动线程的栈、寄存器等)开始遍历整个对象图,标记所有与根对象可达的对象,即被引用的对象
这个过程通过深度优先搜索(DFS)或广度优先搜索(BFS)等算法实现,没有被标记的对象则被认为是垃圾对象
标记前
标记后: 标记所有可达对象
1.2 清除阶段
标记完成后 , 垃圾收集器会遍历整个堆,回收所有没有标记的对象,即垃圾对象
清除完成之后 , 停止 ( STW )
1.3 缺点
在程序的标记阶段到垃圾清除阶段需要 STW , 让程序暂停 , 程序会出现卡顿
正常情况清除标记在停止STW之前 , 将清除标记放在STW之后 , 是为了减少 STW 的时间 , 是一种改进 。不过即使这样 STW 依然是标记回收的主要问题
标记需要扫描整个Heap ( 堆 ) , 而且标记清除只是简单地回收垃圾对象,并不对内存空间进行整理,因此会导致内存碎片的产生,从而影响到堆的空间利用率
2. Go1.5 三色标记
2.1 基本流程
刚开始程序创建的所有对象都标记为白色
首先程序遍历当前的根集合(只遍历一次),将可达对象标记为灰色
遍历灰色节点,并且将上一次的灰色节点变为黑色
重复上一次操作,直到灰色节点下一次没有节点
最后剩下的只有白色和黑色
2.2 无 STW 的问题
已经标记为灰色的对象2,有指针 P 指向白色的对象 3 ( 对象 2 依赖对象 3 )
在还没有扫描到对象2,已经标记为黑色的对象 4 创建指针 q,指向对象 3
以此同时对象2 将指针 p 移除,对象 3 就被挂在了已经扫描完成的黑色的对象
对应上面的2
对应上面的3
出现这种情况 , 因为黑色不会被遍历 , 所以对象3最后就会被垃圾回收,所以需要消灭两个条件中的一个(因为同时满足就会出现对象丢失的现象)
条件一:一个白色对象被黑色对象引用(白色被挂在黑色下)
条件二:灰色对象与它之前的可达关系的白色对象遭到破坏(灰色同时丢了该白色)
2.3 强弱三色不变式
强三色不变式:强制性不允许黑色对象引用白色对象
破坏条件1: 白色对象不会挂在黑色对象下
弱三色不变式: 黑色对象可以引用白色对象,但是白色对象要存在其他灰色对象的引用,或者链路上游存在灰色对象
破坏条件2:灰色对象与它之间的可达关系的白色对象遭到破坏(灰色同时丢了该白色)
3. Go1.8 混合写屏障和三色标记
类似 Hook,handler,回调函数
3.1 插入写屏障
当一个对象被引用时,触发的机制
具体操作:在 A 对象引用 B 对象的时候,B 对象被标记为灰色 ( 这样就不存在黑色对象引用白色对象的情况了 )
//伪代码
添加下游对象(当前下游对象sLot,新下游对象ptr){
//1
标记灰色(新下游对象ptr)
//2
当前下游对象sLot=新下游对象ptr
}
插入任何对象,都会触发插入写屏障,所以为了不影响性能,插入屏障,插入屏障不在栈空间使用
因为插入屏障不在栈空间使用,所以最后栈空间黑色对象引用的白色不会变为灰色
所有灰色节点变为黑色之后,为了确保栈空间的对象引用正常
会将栈空间上的节点全部置为白色,然后重新扫描一遍栈空间,并且此时会加入STW暂停保护 ( 大约需要10-100ms )
插入写屏障的不足: 结束时需要STW来重新扫描栈,大约需要10~100ms
3.2 删除写屏障
当一个对象被删除时,触发的屏障
具体操作: 被删除的对象,如果自身为灰色或者白色,则被标记为灰色 (保护灰色对象到白色对象的路径不会断)
删除写屏障的不足: 回收精度低:一个对象即使被删除了最后一个指向它的指针也依旧可以活过这一轮,在下一轮GC中被清理掉
3.3 混合写屏障
结合了插入写屏障和删除写屏障的优点
具体操作
GC 开始将栈上的对象全部扫描并标记为黑色,(之后不在进行第二次重复扫描,无需STW)
GC 期间,任何在栈上创建的新对象,均为黑色
被删除的对象被标记为灰色
被添加的对象被标记为灰色
变形的弱三色不变式,(结合插入,删除,写屏障两者)
GC 刚刚开始默认都为白色
扫描全部栈对象将可达对象均标记为和黑色
混合写屏障场景一
对象被一个堆空间引用,成为栈对象的下游
将对象 7 添加到对象 1 下游,因为栈不启动写屏障,所以直接挂在下面
对象 4 删除对象7 的引用关系,因为对象4 是堆区,所以触发写屏障,标记被删除的对象 7 为灰色
混合写屏障场景二
对象被一个栈对象删除引用,成为另一个栈对象的下游
新创建一个对象 9 在栈上 ( 混合写屏障模式中,GC 过程中任何新创建的对象均标记为黑色
对象 9 添加下游引用栈对象 3( 直接添加,浅不启动屏障,无屏障效果 )
对象 2 删除对象 3 的引用关系.( 直接删除,栈不启动写屏障,无屏障效果 )
混合写屏障场景三
对象被一个堆对象删除引用,成为另一个堆对象的下游
堆对象 10 添加下游引用堆对象 7,触发屏障机制,被添加的对象标记为灰色,对象7 变成灰色。对象 6 被保护
堆对象 4 删除下游引用堆对象 7,触发屏障机制,被删除的对象标记为灰色,对象7 被标记灰色
混合写屏障场景四
对象从一个栈对象删除引用,成为另一个堆对象的下游
初始情况
堆对象4将之前引用对象7的关系,转移至对象2 ( 对象4删除对象7引用关系 )
对象 7 被对象 4 删除,触发删除写屏障,对象 7 强制转为灰色
这样就保护了对象 7 以及下游节点
评论区