混合写屏障原理

如果是纯粹的插入写屏障是满足强三色不变式的(永远不会出现黑色对象指向白色对象);但是由于栈上对象无写屏障(不 hook),那么导致黑色的栈可能指向白色的堆对象,所以必须假定赋值器(mutator)是灰色赋值器,扫描结束之后,必须 STW 重新扫描栈才能确保不丢对象;STW 重新扫描栈再 goroutine 量大且活跃的场景,延迟不可控,经验值平均 10-100ms;golang 1.5 之后实现的就是这种类型的插入写屏障。



删除写屏障也叫基于快照的写屏障方案,必须在起始时,STW 扫描整个栈(注意了,是所有的 goroutine 栈),保证所有堆上在用的对象都处于灰色保护下,保证的是弱三色不变式;由于起始快照的原因,起始也是执行 STW,删除写屏障不适用于栈特别大的场景,栈越大,STW 扫描时间越长,对于现代服务器上的程序来说,栈地址空间都很大,所以删除写屏障都不适用,一般适用于很小的栈内存,比如嵌入式,物联网的一些程序;并且删除写屏障会导致扫描进度(波面)的后退,所以扫描精度不如插入写屏障;

思考问题:我不整机暂停 STW 栈,而是一个栈一个栈的快照,这样也没有 STW 了,是否可以满足要求?(这个就是当前 golang 混合写屏障的时候做的哈,虽然没有 STW 了,但是扫描到某一个具体的栈的时候,还是要暂停这一个 goroutine 的),不行,纯粹的删除写屏障,起始必须整个栈打快照,要把所有的堆对象都处于灰色保护中才行。



https://zhuanlan.zhihu.com/p/389177621



对比插入写屏障和删除写屏障:



插入写屏障:
插入写屏障哪里都好,就是栈上的操作管不到,所以最后需要对栈空间进行stw保护,然后rescan保证引用的白色对象存活。
删除写屏障:
在GC开始时,会扫描记录整个栈做快照,从而在删除操作时,可以拦截操作,将白色对象置为灰色对象。
回收精度低。
v1.8 混合写屏障机制
讲到这里,如果是你,你会怎么做呢?当然是取其精华,去其糟泊啦…没错,Golang团队,正是结合了这两点,在v1.8版本下引入了混合写屏障机制。下面我们看下混合屏障机制的核心定义:



GC刚开始的时候,会将栈上的可达对象全部标记为黑色。



GC期间,任何在栈上新创建的对象,均为黑色。



上面两点只有一个目的,将栈上的可达对象全部标黑,最后无需对栈进行STW,就可以保证栈上的对象不会丢失。有人说,一直是黑色的对象,那么不就永远清除不掉了么,这里强调一下,标记为黑色的是可达对象,不可达的对象一直会是白色,直到最后被回收。



堆上被删除的对象标记为灰色



堆上新添加的对象标记为灰色



https://www.cnblogs.com/cxy2020/p/16321884.html


Category golang