记录Golang中垃圾回收机制学习。
基本概念
- GC - Garbege Collection: 垃圾回收
- 内存管理
- 三色标记法
- 自动释放
- STW(StopTheWorld)(性能瓶颈之一):暂停进程,清除垃圾,恢复进程
Go1.3以前
标记-清除方法(MarkAndSweep)
整体过程需要STW
流程
程序可以引用多个对象,对象亦可以引用其他对象,以及孤立对象。
- 可达对象:通过引用路径可以抵达的对象
- 不可达对象:孤立的,无法通过引用路径到达的对象
for(直至生命周期结束){STW -> 根据引用路径标记可达对象 -> 清除未标记对象 -> 停止STW}
缺陷
- STW:程序暂停,出现卡顿 (‼️重要问题)
- 标记需要扫描整个heap
- 清除数据导致heap碎片
- 缩短STW:通过将清除对象移到停止STW后方,缩短整体STW的时间
Go1.5
三色标记法
堆空间启动写屏障,栈空间不启动,全部扫描完后,需要重新扫描一次栈空间(STW)
流程
- 白色标记
- 灰色标记
- 黑色标记
- 程序创建初期,全部标记为白色,所有对象加入白色标记集合
- 将程序跟节点集合展开,遍历RootSet(只遍历一次,不递归)标记灰色节点
- 遍历灰色标记集合标记可达对象为灰色,同时将遍历过的灰色的节点标记为黑色节点
- 循环上一步直至无任何灰色标记节点
- 回收所有白色对象(垃圾)
三色标记无STW的问题
在无STW的时候,在扫描过程中,出现黑色对象创建某一指针引用到某白色对象,于此同时灰色对象删除了对该白色对象的引用,在原算法设计中,因为黑色节点不会被再次扫描,此时该白色对象将不会被标记为灰色节点,而是被等待回收清除。
最不利状况:
- 一个白色对象被黑色对象引用
- 灰色对象与它之间的可达关系的白色对象遭到破坏
强三色不变式/弱三色不变式
强:强制性的不允许黑色对象引用白色对象(可以引用灰色对象)「破坏条件一」 弱:黑色对象可以引用白色(但要求白色对象存在其他灰色对象对它的引用或者可达链路上游存在灰色对象)「破坏条件二」
屏障机制
为了解决无STW导致的问题,引用屏障机制(实现强/弱三色不变式)
在正常执行流程中,添加额外的判断来实现屏障机制。
插入写屏障
对象在被引用时,触发该机制,防止影响栈性能故不在栈上使用,在堆上使用
在A对象引用B对象,B对象被标记为灰色(此时不存在黑色对象引用白色对象的情况,因为白色对象会被强制变成灰色)
栈再扫描:在准备回收白色对象前,重新遍历栈空间,此时使用STW保护栈。
不足:结束时需要STW来重新扫描栈,约10~100ms
删除写屏障
对象在被删除时,触发该机制
被删除的对象,如果自身为灰色或者白色,那么被标记为灰色,保护灰色对象到白色对象的路径不会断。
不足:回收精度低,一个对象即使被删除也可以活过该轮回收,在下一轮才回收。
Go1.8
三色标记法+混合写屏障机制
栈空间不启动,堆空间启动,整体过程几乎不需要STW,效率较高
- GC开始将栈上可达对象全部扫描并标记为黑色(之后不再进行第二次重复扫描,无需STW)
- GC期间,任何在栈上创建的新对象,均为黑色
- 被删除的对象标记为灰色
- 被添加的对象标记为灰色