V8 垃圾回收机制
1. 分代垃圾回收
V8 将内存分为新生代和老生代,根据对象的存活时间采用不同的回收策略。
- 新生代:存放生命周期短的对象,内存较小(64 位系统为 32MB,32 位系统为 16MB),采用 Scavenge 算法。
- 老生代:存放生命周期长或常驻内存的对象,内存较大(64 位系统为 1.4GB,32 位系统为 0.7GB),采用 Mark-Sweep 和 Mark-Compact 算法。
2. 新生代垃圾回收:Scavenge 算法
- Cheney 算法:将新生代内存分为 From 空间 和 To 空间,新对象分配到 From 空间。当 From 空间满时,GC 会将存活对象复制到 To 空间,非存活对象被释放,随后 From 和 To 空间角色互换。
- 晋升条件:
- 对象经历过一次 Scavenge 回收后仍存活。
- To 空间占用超过 25%(避免影响后续内存分配)。
3. 老生代垃圾回收
- Mark-Sweep(标记清除):
- 标记阶段:遍历堆中所有对象,标记存活对象。
- 清除阶段:清除未标记的对象。缺点是会产生内存碎片。
- Mark-Compact(标记整理):
- 在 Mark-Sweep 基础上,将存活对象向一端移动,清理边界外的内存,解决内存碎片问题。
- 触发条件:
- 空间不足时启动 Mark-Sweep。
- 内存碎片过多时启动 Mark-Compact。
4. 优化策略
- 增量标记(Incremental Marking):
- 将标记过程分解为多个小任务,与 JavaScript 应用逻辑交替执行,减少主线程停顿时间。
- 惰性清理(Lazy Sweeping):
- 延迟清理非活动对象,优先执行 JavaScript 逻辑,按需清理内存。
- 并发标记与清理:
- 在后台线程执行标记和清理操作,主线程继续运行 JavaScript 代码,进一步减少停顿时间。
- 三色标记法与写屏障:
- 使用白、灰、黑三色标记对象状态,写屏障机制确保黑色对象引用白色对象时,白色对象被标记为灰色,避免漏标。
5. 内存限制与触发条件
- 内存限制:
- 64 位系统:新生代 32MB,老生代 1.4GB。
- 32 位系统:新生代 16MB,老生代 0.7GB。
- 触发条件:
- 新生代:From 空间满时触发 Scavenge。
- 老生代:空间不足或内存碎片过多时触发 Mark-Sweep 或 Mark-Compact。
6. 性能问题与改进
- 全停顿(Stop-The-World):
- 垃圾回收期间暂停 JavaScript 执行,影响应用性能。
- 改进措施:
- 增量标记、惰性清理、并发标记等技术显著减少停顿时间,提升用户体验。
7. 内存泄漏与避免
- 常见原因:
- 未释放的全局变量、闭包、未清理的定时器或事件监听器。
- 避免方法:
- 及时释放不再使用的对象引用。
- 使用工具(如 Chrome DevTools)监控内存使用情况。
8. 总结
V8 的垃圾回收机制通过分代回收、增量标记、并发清理等优化策略,实现了高效的内存管理。理解其工作原理有助于编写高性能的 JavaScript 代码,并避免内存泄漏等问题。
思维导图建议结构:
- 分代回收
- 新生代
- 老生代
- 回收算法
- Scavenge
- Mark-Sweep
- Mark-Compact
- 优化策略
- 增量标记
- 惰性清理
- 并发标记
- 内存限制与触发条件
- 性能问题与改进
- 内存泄漏与避免
希望这份整理内容能帮助你更好地理解 V8 垃圾回收机制,并制作出清晰的思维导图!