v8引擎采用分代回收机制,基于代际假说将堆内存划分为新生代(scavenge算法)和老生代(mark-sweep与mark-compact协同),辅以增量标记、并发标记和延迟清理等优化,兼顾回收效率与性能平滑。

V8 引擎的分代回收不是凭空划分,而是基于“代际假说”——绝大多数对象生命周期极短,只有少数能长期存活。它把堆内存明确划分为新生代(Young Generation)和老生代(Old Generation),并为各自匹配最合适的回收算法和策略,从而兼顾效率与吞吐。
新生代回收:Scavenge 算法主导,快而轻量
新生代空间小(通常 1–8 MB),专用于存放新创建的对象。V8 将其均分为两个半区:From 空间(当前使用)和 To 空间(空闲)。
- 新对象一律分配在 From 空间;
- 当 From 空间快满时触发回收;
- GC 遍历 From 空间,只把存活对象复制到 To 空间;
- 复制过程中,若某对象已经历过两次 Scavenge,或 To 空间放不下,就直接晋升(promote)到老生代;
- 复制完成后,清空 From 空间,并交换 From/To 角色,下轮回收继续。
这种复制式回收几乎不产生碎片,且只处理少量存活对象,因此非常迅速。
老生代回收:标记-清除 + 标记-整理协同工作
老生代存放长期存活、体积较大或已晋升的对象,空间大、对象多,无法承受频繁复制。
- 主要采用 Mark-Sweep(标记-清除):从根(全局对象、栈中变量等)出发遍历可达对象并标记;未被标记的即为垃圾,直接回收;
- 但清除后易产生内存碎片,影响后续大对象分配;
- 所以当碎片达到阈值,会触发 Mark-Compact(标记-整理):把所有存活对象向内存一端移动,再统一清理尾部空白区域,实现内存“压实”。
回收触发不是定时,而是按需驱动
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 新生代 GC 频繁(毫秒级),由内存分配速率和空间水位决定;
- 老生代 GC 较少(秒级甚至更长),通常由以下条件之一触发:
- 老生代空间增长超过设定阈值;
- 新生代晋升对象过多,压力传导;
- 页面空闲或主线程暂停间隙(配合增量标记)。
优化机制让分代更“隐形”也更高效
- 增量标记(Incremental Marking):把老生代的标记过程拆成多个微任务,在 JS 执行间隙穿插进行,避免长时间卡顿;
- 并发标记(Concurrent Marking):部分标记工作由辅助线程并行执行,不阻塞主线程;
- 延迟清理(Lazy Sweeping):清除阶段也不一次性扫完,而是按需逐步释放,进一步平滑性能毛刺。
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










