[Golang] Golang GC(三色标记法)

一、GO 1.3之前的标记删除

1.第一步,暂停程序业务逻辑,找出不可达对象,和可达对象
2.第二部,开始标记,程序找出它所有的可达对象,并做上标记
3.标记完之后,开始清除未标记对象
4.停止暂停,让程序继续跑。然后循环重复这个过程直到process程序生命周期结束
请添加图片描述

标记-清除方法的缺点

1.stw(stop the world)让程序暂停,程序出现卡顿
2.标记需要扫描整个heap(堆)
3.清除数据会产生heap碎片
4.并发时,导致先前未被标记的误删除

改进

1.缩小stw范围,将清除挪出来,先恢复程序,再清除
2.->使用三色标记法

二、三色标记法(GO V1.5之后)

程序RootSet根节点关联着对象1和对象4,而对象1关联对象2,对象2关联对象3,对象7引用着对象2;另一个分支,对象4引用对象5;对象6处于游离状态。下图展示的就是以上所表述的内存情况,从可达性分析得到,GC应该回收对象6与对象7,那么三色标记法如何识别到对象6和对象7呢?

三色标记法是用于寻找从程序RootSet所关联的对象出发,只遍历一次,为每一个对象标记颜色。标记结束后,被标记为白色的对象需要释放空间,而被标记为黑色的对象继续保留。一次三色标记法结束后,是不存在被标记为灰色的对象的。

如图下所示,第一步我们把所有的对象都标记为白色。请添加图片描述
第二步,把在程序根结点集合RootSet里的对象标记为灰色。如下图所示,标记为灰色的是对象1和对象4。请添加图片描述
第三步,遍历标记为灰色的对象,找到关联的对象,并标记为灰色,同时把自己标记为黑色。如下图所示,遍历灰色对象发现:对象1关联对象2,对象4关联对象5。那么,把对象2和对象5标记为灰色,同时对象1和对象4标记为黑色。请添加图片描述
此时,被标记为灰色的对象是对象2和对象5。第四步,重复第三步,遍历寻找灰色对象所关联的对象,并标记为灰色。如下图所示,对象2关联对象3,对象5没有关联对象。那么把对象3标记为灰色,对象2和对象4标记为黑色。请添加图片描述
到了这一步,还剩对象3,对象6和对象7没处理。我们继续,第五步,我们发现对象3没有关联对象,那么如下图,把对象3标记为黑色。

请添加图片描述
终于把全部对象标记颜色,此时释放被标记为白色的对象的内存空间,保留被标记为黑色的对象,已经不存在被标记为灰色的对象了。

假设三色标记无STW,会发生什么:

参考视频
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
三色标记最不希望发生的事:
1.一个白色对象被黑色对象引用(条件一)
2.灰色对象与它之间的可达关系的白色对象遭到破坏(条件二)
(两个条件同时满足,对象丢失)

强弱三色不变式:

强三色不变式:不许黑色对象引用白色对象(破坏条件一)
弱三色不变式:黑色可以引用白色,白色对象存在其他灰色对象对他的引用,或者可达它的链路上游存在灰色对象(破坏条件二)

三、插入写屏障

想要实现强弱三色不变式,需要学习插入写屏障

插入屏障(不在栈上使用

对象被引用时 触发的机制

具体操作:在A对象引用B对象时,B对象被标记为灰色(将B挂在A的下游,B必须被标记为灰色)
满足:强三色不变式(不存在褐色对象引用白色对象的情况了,因为白色会被强制变为灰色)

//伪代码
添加下游对象(当前下游对象slot,新下游对  象ptr){
	//1
	标记灰色(新下游对象ptr)
	//2
	当前下游对象slot = 新下游对象ptr
}

//场景
A.添加下游对象(nil,B) //A之前无对象,新加B,B标记为灰
A.添加下游对象(C,B) // A 将下游对象更换为B, B被标记为灰色

插入写屏障的不足

为了保证栈的速度,因此不会给栈加插入屏障
那么扫描结束时需要stw来重新扫描栈,大约需要10-100ms

删除屏障

对象被删除时 触发的机制
具体操作:被删除的对象,如果自身为灰色或者白色,那么被标记为灰色
满足:弱三色不变式.(保护灰色对象到白色对象的路径不会断)

//伪代码
添加下游对象(当前下游对象slot,新下游对  象ptr){
	//1 注:删除就是添加一个空
	if(当前下游对象slot是灰色||当前下游对象slot是白色){
		灰色标记(当前下游对象slot)
	}
	//2
	当前下游对象slot = 新下游对象ptr
}

A.添加下游对象(B,nil) //A对象,删除B对象的引用。B被A删除,被标记为灰(如果B之前为白)
A.添加下游对象(B,C) //A对象,更换下游对象为C。B被A删除,被标记为灰(如果B之前为白)

删除写屏障的不足

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

Go V1.8的三色标记法+混合写屏障机制

具体操作:
1.GC开始将栈上的对象全部扫描标记为黑色(之后不再进行二次重复扫描,无需stw)
2.GC期间,任何在栈上创建的新对象,均为黑色
3.被删除的对象标记为灰色(栈+堆)
4.被添加的对象标记为灰色

满足:变形的弱三色不变式(结合了插入、删除写屏障两者的优点)

//伪代码
添加下游对象(当前下游对象slot,新下游对  象ptr){
	//1
	标记灰色(当前下游对象slot)//只要当前下游对象被移走,就标记为灰色
	//2
	标记灰色(新下游对象ptr)
	//3
	当前下游对象slot = 新下游对象ptr
}

在这里插入图片描述
在这里插入图片描述

场景

场景一

对象被一个堆对象删除引用,成为栈对象的下游

//伪代码
//前提:堆对象4->对象7 = 对象7; 对象7 被 对象4 引用
栈对象1 -> 对象7 = 堆对象7; // 将堆对象7 挂在 栈对象1 下游
堆对象4 -> 对象7 = null // 对象4 删除引用 对象7

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

场景二

对象被一个栈对象删除引用,成为另一个栈对象的下游

//伪码
new 栈对象9;
对象9 -> 对象3 = 对象3;//将栈对象3 挂在 栈对象9 下游
对象2 -> 对象3 = null; //对象2 删除引用 对象3

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

场景三

对象被一个堆对象删除引用,成为另一个堆对象的下游

//伪码
堆对象10 -> 对象7 = 对象7;//将栈对象7挂在 栈对象10下游
堆对象4 -> 对象7= null; //对象4 删除引用 对象7

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

场景三

对象被一个栈对象删除引用,成为另一个堆对象的下游

//伪码
栈对象1 ->对象2 = null; //对象1 删除引用 对象2
栈对象4 -> 对象2 = 栈对象2;//对象4 添加 下游 栈对象4
栈对象4 -> 对象7 = null; //对象4 删除引用 对象7

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值