golang混合写屏障实现
写屏障只应用在堆上应用,栈上部启用。
GC开始将栈上的对象全部扫描并标记为黑色。
GC期间,任何在栈上创建的新对象,均为黑色。
被删除的对象标记为灰色。
被添加的对象标记为灰色。
golang gc流程
STW(StopTheWorld)开启写屏障,记录数据段以及栈中roots的必要信息
StartTheWorld开始标记,此时mutator(用户程序)和GC标记并发执行
标记完成再次STW,关闭写屏障
StartTheWorld进入轻扫阶段
其中标记阶段有一个问题很多文章没有解释清楚,就是,栈上的黑色对象是否会引用到一个堆上的白色对象。因为栈是没有写屏障的,如果栈上的黑色对象引用了堆上的白色对象,被引用的白色对象就会被GC错误回收。
例如下图所示的场景:
A如果引用了D,同事B删除了对D的引用,那么D不就被错误的回收了吗。
实际这种情况时不会发生的:
- 对于某个goroutine的栈扫描是原子的操作,会暂停此goroutine,标记结束后栈对象全部为黑色。
- 已被扫黑的栈,引用的堆上的对象至少是灰色。(比如C对象)。所以不可能发生同栈下引用改变会影响GC的问题,因为白色对象都在保护之中。
- 不可能发生上述的跨栈的引用。因为“对象不是从天上掉下来的”。因为A没有路径能够抵达D。
- GC期间栈上新建的对象全是黑色,即使逃逸到堆上,也是黑色,所以A如果引用了新创建的对象也会是黑色,而不会发生错误的回收
参考:
golang 垃圾回收(五)深入剖析混合写屏障
Golang三色标记+混合写屏障GC模式全分析
go: GC时写屏障与栈的引用变化