Skip to content
目录

3. 堆布局与垃圾回收

V8 的 GC 重点不是背源码类名,而是讲清楚:为什么分代、年轻代怎么收、老年代怎么收、如何降低停顿

分代假说

V8 堆主要分为 新生代老生代

分代的依据是:大多数对象生命周期很短,刚创建不久就会死亡。把新对象集中放在新生代,可以让频繁 GC 的成本更低。

新生代

新生代常见思路是 复制回收

  • 对象先分配在新生代。
  • GC 时只复制存活对象。
  • 多次存活后晋升到老生代。

复制回收的优点是分配快、整理自然完成;缺点是需要预留空间,内存利用率有代价。

现代 V8 也有年轻代标记清除相关路径,可以根据配置和场景做取舍。中一般说“新生代偏复制,老生代偏标记整理”即可。

老生代

老生代对象生命周期更长,如果频繁复制成本太高,所以主要使用 Mark-Compact

  1. 从根对象出发标记可达对象。
  2. 清理不可达对象。
  3. 必要时压缩整理,减少内存碎片。

降低停顿

GC 最大问题是 STW,也就是暂停 JS 执行。V8 通过以下方式降低卡顿:

  • 增量标记:把一次大标记拆成多步。
  • 并发标记 / 清理:部分工作放到后台线程。
  • 任务调度:在合适时机触发 minor GC,避免分配路径突然卡住。

总结

V8 GC 的核心是分代回收:新生代对象多、死得快,适合低成本回收;老生代对象活得久,适合标记和整理。为了减少卡顿,V8 会把 GC 工作增量化、并发化,并通过写屏障维护正确性。

MIT License.