一句话总结:写屏障机制作用于GC过程,目的是为了维护在垃圾回收的收集过程中数据的一致性,实现GC的并发标记、三色不变性和低延迟,其实现是使用了混合写屏障(hybrid write barrier)技术,结合了Dijkstra风格的写屏障和Yuasa风格的写屏障的优点。

写屏障的工作方式

写前屏障(Dijkstra风格): 在指针修改前,将旧指针指向的对象标记为灰色

// 伪代码
func writePointer(slot *unsafe.Pointer, ptr unsafe.Pointer) {
    shade(*slot)  // 标记旧值
    *slot = ptr   // 实际写入
}

写后屏障(Yuasa风格): 在指针修改后,将新指针指向的对象标记为灰色

// 伪代码
func writePointer(slot *unsafe.Pointer, ptr unsafe.Pointer) {
    *slot = ptr   // 实际写入
    shade(ptr)     // 标记新值
}

写屏障的具体规则

在Go的混合写屏障实现中:

  1. 对全局变量和堆对象的写操作会触发写屏障

  2. 对栈上的写操作通常不需要写屏障(因为栈是根对象)

  3. 写屏障会确保:

    • 被覆盖的旧指针指向的对象被标记

    • 新写入的指针指向的对象被标记

写屏障的优化

Go运行时对写屏障做了多种优化:

  1. 无栈屏障: 栈上的写操作通常不启用写屏障,因为栈会被重新扫描

  2. 批量处理: 多个写操作可以批量处理以减少开销

  3. 条件启用: 只在GC的标记阶段启用写屏障

写屏障的重要性

写屏障使得Go能够实现:

  1. 并发标记: 用户程序可以和标记过程同时运行

  2. 三色不变性: 确保不会丢失任何可达对象的标记

  3. 低延迟: 减少了STW(Stop-The-World)的时间

 

内容主要来源于:Go语言写屏障机制详解