文章

go GC

复习用

go GC

基础知识

go的垃圾回收是没有分代,不整理,并发的三色标记清扫算法

go1.3标记清除

从gc root出发,标记所有可达对象。最后扫描整个head,将没有标记的对象(不可达对象)清除。但缺点是STW、需要扫描整个heap、清除后会产生大量碎片。

为了缓解STW来带的停止长时间用户程序执行,标记之后马上停止STW,清除阶段与用户程序并行执行。

go1.5三色标记

开始时所有对象标记为白色,从gc root出发做BFS,将可达对象标记为灰色。然后从这些灰色节点出发做BFS,并将这些节点标记为黑色,将可达对象标记为灰色,重复这个过程,最终整个程序只有黑色和白色对象,清除其中的白色对象。

和标记清除的本质区别是,三色标记是逐层标记的,在其中某些阶段可以与用户代码并发执行,而不用STW整个过程并一次性遍历标记清除。

强弱三色不变式

三色标记gc如果和用户代码并发执行,对于以下并发序列:

1
用户解除a对b(b在堆上)的引用并且此时b为白色 -> 切换到gc并标记a为黑色 -> 切换回用户程序,a又引用回b

如果b没有其他灰色对象直接引用,或者b没有被其他灰色对象间接引用的话,比如c(灰)->d(白)->b(白),那么b将会在清除阶段被回收,导致用户后续通过a访问b时出现错误。

因此只要遵循强三色不变式

1
不允许黑色对象引用白色对象

或者遵循弱三色不变式

1
黑色对象可以引用白色对象,但是必须有灰色对象直接或间接引用这个白色对象

就能做到保证不会错误回收用户正在使用的对象。

屏障

屏障是实现强弱三色不变式的手段。所谓屏障就是hook,在引用/删除引用对象之前/之后触发hook做一些事情。

 插入屏障删除屏障
效果在A引用B的时候,将B标记为灰色在A删除对B的引用时,将B标记为灰色
目的满足强三色不变式满足弱三色不变式
不足标记结束的后需要STW重新扫描栈B可能确实是垃圾,这种情况下B会延迟到下一轮才被回收

Go1.8后引入混合写屏障机制:

  1. gc开始的时候将栈上所有对象标记为黑色

参考链接🔗

【欧长坤】go语言原本-垃圾回收

本文由作者按照 CC BY 4.0 进行授权