前置概念:两种经典屏障

理解混合写屏障前,需先了解其两个“双亲”:

  • 插入写屏障 (Dijkstra):每当建立新引用 A.next = B 时,强制将 新对象 B 变灰。它保护的是“新欢”,确保新建立的联系不被漏标。
  • 删除写屏障 (Yuasa):每当断开旧引用 A.next = nil 时,强制将 旧对象 B 变灰。它保护的是“旧爱”,确保断开的路径仍能被追踪。

混合写屏障:融合与进化

一句话定义

混合写屏障(Hybrid Write Barrier)是 Go 1.8 引入的垃圾回收优化机制。它通过在堆内存操作时同时执行“提拔新引用”与“保护旧引用”的双向策略,来补偿栈空间不开启屏障带来的安全风险。该机制彻底消除了标记结束阶段需要暂停程序来重新扫描栈(Stack Rescan)的过程,将 Stop The World (STW) 时间缩减至亚毫秒级。

屏障机制对比

核心技巧:提拔下游白色对象,而非退回黑色对象。

屏障类型触发动作具体做法维护原则评价
插入A.next = B新引用 B 标灰强三色不变性简单,但需 STW 重扫栈
删除A.next = nil旧引用 B 标灰弱三色不变性精度低(浮动垃圾多)
混合建立/断开新旧引用 均标灰结合两者消除重扫,性能极佳

核心规则:性能与安全的极致平衡

设计哲学:牺牲极小内存(浮动垃圾),换取几乎无感的 STW 时长。

维度核心逻辑设计意图
性能栈区域全黑:STW 一次性扫描栈指针并标黑消除重扫:栈操作从此免除屏障损耗
性能栈新对象全黑:GC 期间栈上新对象直接标黑无需回头:确保新对象在本轮绝对安全
安全被删除引用变灰:堆对象断开引用时,旧引用变灰补偿栈风险:防止对象因路径断开被误杀
安全新添加引用变灰:堆对象建立新引用时,新引用变灰强化路径:确保新引用关系被追踪
浮动垃圾

指在本轮 GC 中本该被回收,但因为写屏障的保护(变黑)而被迫存活到下一轮的对象。

为什么需要它?

Go 在“性能-安全”博弈中选择了 “堆上双向保护”对冲“栈上无屏障”

知识扩展

  • STW 优化:STW 仅存在于开启和关闭屏障的瞬间。
  • 流转路径:被提拔对象遵循 白 -> 灰 -> 黑。变黑即获“本轮免死金牌”。
  • 触发条件:仅在 堆对象 指针修改时触发,栈上修改不触发。