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后引入混合写屏障机制:
- gc开始的时候将栈上所有对象标记为黑色
参考链接🔗
本文由作者按照 CC BY 4.0 进行授权