Skip to content
目录

4. 写屏障、Remembered Set 与跨代引用

写屏障是 GC 里很高频的点。它本质上是在对象字段写入时,顺手记录一些信息,避免 GC 漏标对象。

为什么需要写屏障

最典型的问题是 老年代对象引用新生代对象

js
oldObj.child = newObj

年轻代 GC 通常只扫描新生代。如果不记录这条老到新的引用,newObj 可能明明还被引用,却被错误回收。

因此 V8 会用 remembered set 记录这类跨代引用。

remembered set

remembered set 记录的是“老年代里哪些槽位可能指向新生代”。这样年轻代 GC 不需要扫描整个老年代,只扫描这些被记录的槽位。

它解决的是效率问题:既保证不漏标,又避免每次 minor GC 都全堆扫描。

增量标记中的写屏障

增量 / 并发标记时,JS 代码还在继续修改对象引用。写屏障还要维护三色标记不变式,避免出现 黑对象指向白对象,导致白对象被误回收。

所以写屏障不只服务分代 GC,也服务增量标记的正确性。

什么时候可以省略

不是所有写入都需要屏障,例如:

  • 写入的是 Smi 这类非堆对象。
  • 写入只读堆对象。
  • 对刚分配的新生代对象做初始化写入,且还没经过 GC 安全点。

里不用展开证明,只要说明:省略写屏障必须由 GC 不变式保证,不能随便跳过。

总结

写屏障是在对象引用写入时维护 GC 辅助信息。它主要解决跨代引用和增量标记正确性问题;remembered set 则让年轻代 GC 不必扫描整个老年代。

MIT License.