三色标记法
Go语言从1.5开始使用并发的三色标记法进行垃圾回收,可以将其归纳成以下几个步骤:
- 从灰色对象的集合中选择一个灰色对象并将其标记成黑色;
- 将黑色对象指向的所有对象都标记成灰色,保证该对象和被该对象引用的对象都不会被回收;
- 重复上述两个步骤直到对象图中不存在灰色对象;
当三色的标记清除的标记阶段结束之后,应用程序的堆中就不存在任何的灰色对象,只能看到黑色的存活对象以及白色的垃圾对象,垃圾收集器可以回收这些白色的垃圾。
垃圾回收过程
1、标记准备阶段
这一阶段首先会清扫上一次GC遗留的垃圾对象,并开启用于标记的协程,统计需要扫描的任务数量,开启写屏障,启动标记协程等,这些步骤需要在STW(Stop The World)时进行。
Go语言中后台标记协程消耗的CPU为25%。
2、并发标记阶段
这一阶段不需要STW,当前的P会优先执行标记协程。
首先将根对象入队,Go语言中根对象包括全局变量、span中的finalizer(finalizer是Go语言中对象绑定的析构器)的任务数量,以及所有协程栈。
然后扫描灰色对象。在标记期间会循环的从本地标记队列获取灰色对象,灰色对象扫描到的白色队列会被放入标记队列,如果扫描到已经被标记的对象则会被忽略,一直到队列中任务为空为止。
根据屏障技术的原则,在并发标记阶段写入和删除对象时将可能活着的对象标记为灰色。Go1.8以后引入了混合写屏障。
3、标记终止阶段
标记终止阶段会再次开启STW,并完成一些指标,如统计用时、统计强制开启GC的次数、更新下一次GC需要达到的堆目标、关闭写屏障等。默认的目标内存是上一次GC目标内存的2倍。
4、清理阶段
这一阶段会关闭STW,然后开启垃圾清扫协程,Go语言垃圾清扫采用懒清扫的策略,因此下一次触发GC时可能会有上一次没有被清扫的内存。
参考: Go语言垃圾收集器