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 不必扫描整个老年代。