写屏障(Write Barrier)是编译器在指针赋值操作中插入的一段额外逻辑

用于在并发标记阶段追踪指针变化,确保 GC 不会遗漏任何存活对象。

痛点:为什么需要写屏障?

三色标记法 的并发阶段,业务代码和 GC 扫描同时运行。如果没有监控,会发生“对象丢失”:

场景步骤动作描述后果
1. 扫描完毕GC 已将对象 A 标记为黑色(已扫描)A 不会再被扫描
2. 指针变动业务代码让 A 指向了一个白色对象 BGC 看不到 B
3. 引用断开B 的其他原始引用被删除B 成了孤儿
结果B 被误判为垃圾回收掉程序崩溃 (Dangling Pointer)

对策:混合写屏障 (Hybrid Write Barrier)

Go 1.8+ 采用混合写屏障,结合了“插入”和“删除”两种策略的优点,实现了栈上不开启写屏障的极致性能。

核心逻辑

当执行 *slot = ptr (将指针 ptr 写入内存 slot) 时:

策略类型动作 (Shade)目的
删除屏障标记 *slot (旧值) 为灰色保护被删除引用的对象,确保本轮存活
插入屏障标记 ptr (新值) 为灰色保护新引用的对象,防止被 GC 漏掉

伪代码实现

// 编译器自动插入的逻辑
write_barrier(slot, ptr):
    shade(*slot) // 标记旧对象为灰色
    shade(ptr)   // 标记新对象为灰色
    *slot = ptr  // 真正的赋值操作

生命周期

写屏障并非全程开启,它仅在 GC 的特定阶段工作:

  1. 开启:在 Mark Prep 阶段的短暂 STW 期间开启。
  2. 运行:在整个 并发标记 (Concurrent Mark) 阶段持续监控。
  3. 关闭:在 Mark Termination 阶段的 STW 期间关闭。

性能权衡

维度影响优化对策
CPU 开销每次指针赋值增加几条指令仅在堆 (Heap) 上开启,栈 (Stack) 上不开启
内存一致性确保并发安全配合 STW 进行最后的栈扫描。

一句话总结:写屏障通过在指针修改时“多做一点事”,换取了 GC 不需要长时间停顿程序的能力。