golang的gc使用的是三色标记法&混合写屏障
技术
三色标记
- 创建黑、灰、白 三个集合
- 所有对象加入到 白色 集合中
- 遍历所有root对象, 把遍历到的对象加入到 灰色 集合
- 遍历所有灰色对象, 把灰色对象引用的白色对象加入到灰色集合, 自身加入到黑色集合
- 重复步骤4. , 直到灰色集合没有对象
- 清除白色集合中的对象
这里面会有一个问题,因为标记过程和用户过程是同时进行的, 可能会导致部分被引用的对象没有正确加入到黑色集合中从而被错误清理掉, 因此加入了混合写屏障
-
插入写屏障
对象被引用时触发的机制(只在堆内存中生效):赋值器这一行为通知给并发执行的回收器,被引用的对象标记为灰色
缺点:结束时需要STW来重新扫描栈,标记栈上引用的白色对象的存活 -
删除写屏障
对象被删除时触发的机制(只在堆内存中生效):赋值器将这一行为通知给并发执行的回收器,被删除的对象,如果自身为灰色或者白色,那么标记为灰色
缺点:一个对象的引用被删除后,即使没有其他存活的对象引用它,它仍然会活到下一轮,会产生很大冗余扫描成本,且降低了回收精度
GC流程
一次完整的垃圾回收会分为四个阶段,分别是标记准备、标记开始、标记终止、清理:
-
标记准备(Mark Setup):打开写屏障(Write Barrier),需 STW(stop the world)
-
标记开始(Marking):使用三色标记法并发标记 ,与用户程序并发执行
-
标记终止(Mark Termination):对触发写屏障的对象进行重新扫描标记,关闭写屏障(Write Barrier),需 STW(stop the world)
-
清理(Sweeping):将需要回收的内存归还到堆中,将过多的内存归还给操作系统,与用户程序并发执行