写屏障解决的是并发标记的'误杀'问题。三色标记与用户代码并发执行时,用户可能修改引用关系:若一个已扫描完的黑色对象新增对白色对象的引用,而白色对象唯一的引用路径恰好断开,GC 会把活对象当垃圾回收,造成程序崩溃。写屏障是在指针写入时由编译器插入的一小段代码,把相关对象重新染色,维持三色不变式。
Go 1.8 起采用混合写屏障(hybrid write barrier),结合 Dijkstra 插入屏障(新指向的对象染灰)和 Yuasa 删除屏障(被覆盖的旧引用染灰)。它的关键收益是栈不需要在标记结束时重新扫描——早期版本 re-scan 所有 goroutine 栈导致几十毫秒的 STW,混合写屏障把 STW 压到亚毫秒级。代价是每次指针写入多了几个分支判断的微小开销,以及屏障本身占用少量 CPU。
// 写屏障由编译器插入,不可见,但可以观察其效果:
// GODEBUG=gctrace=1 中 stw 时间通常 <1ms
易错点:写屏障只保护堆指针写入的染色,不解决数据竞争;它不是内存屏障(memory barrier),两件事不要混淆。追问方向:强弱三色不变式的区别、为什么栈对象不直接加屏障(性能考虑)。