内存管理
JavaScript 自动垃圾回收。
引用计数
对象引用计数为0时回收。
1 | let obj = { name: 'Alice' } |
循环引用问题
1 | let obj1 = {} |
标记清除
主流算法。
- 标记根可达对象
- 清除未标记对象
内存泄漏
- 全局变量
- 闭包
- DOM 引用
- 定时器
优化
- 避免全局变量
- 及时清除引用
- 使用 WeakMap/WeakSet
总结
JavaScript 的垃圾回收机制自动管理内存,最常见的是标记-清除算法。深入理解 GC 有助于写出内存高效的程序,并避免性能陷阱。
垃圾回收算法
标记-清除 (Mark-and-Sweep)
- 从根对象开始标记可达对象
- 清除未被标记的对象
引用计数 (Reference Counting)
为每个对象维护一个引用计数;计数为0时回收。存在循环引用问题。
分代回收 (Generational GC)
对象根据存活时间分代,新生代回收频繁,老生代回收较少。
增量回收与并行回收
现代浏览器支持将 GC 工作拆分成小块并在后台线程执行,减少停顿时间。
内存管理技巧
- 避免建立大规模长生命周期对象
- 使用
const避免意外重新赋值 - 对 DOM 对象使用
WeakMap保存元数据
WeakMap/WeakSet 的意义
WeakMap 的键是弱引用,垃圾回收不会因为键存在而阻止其回收:
1 | let wm = new WeakMap(); |
诊断工具
- Chrome DevTools:Memory 面板、Heap snapshot、Allocation instrumentation
- Firefox:Memory 工具
- Node.js:
--inspect模式、heapdump模块
手动触发垃圾回收
在 Chrome 的开发者控制台中可以调用 window.gc()(需要开启 --js-flags="--expose-gc")。
常见问题
- 大量对象未被清除:检查是否存在闭包、全局变量或 DOM 事件监听未释放。
- 内存增长缓慢:可能是分代回收暂时未触发。
- 性能抖动:GC 停顿影响 UI,可通过减少分配和简化对象关系来优化。
专业建议
- 在性能敏感的循环中尽量避免创建临时对象
- 使用
requestAnimationFrame合理安排 UI 更新 - 在大型项目中定期分析 heap snapshot,查找泄漏或不必要的保留
相关资源
- V8 的垃圾回收原理
- SpiderMonkey GC 文档
- Google Chrome 开发者博客关于性能优化的系列文章
了解垃圾回收有助于写高效代码。现代引擎很智能,但仍需注意内存使用。
跨平台差异
不同引擎(V8、SpiderMonkey、JavaScriptCore)在 GC 实现上略有差异,但基本原理相似。调优时应在目标平台上进行测试。
内存碎片
频繁分配和释放大对象可能导致内存碎片,影响性能。可以使用对象池(object pool)复用对象。
GC 可视化
使用 Chrome about://tracing 或 DevTools 中的 Timeline 记录 GC 活动,观察停顿时间。
垃圾回收补充行 1
垃圾回收补充行 2
垃圾回收补充行 3
垃圾回收补充行 4
垃圾回收补充行 5
垃圾回收补充行 6
垃圾回收补充行 7
垃圾回收补充行 8
垃圾回收补充行 9
垃圾回收补充行 10
垃圾回收补充行 11
垃圾回收补充行 12
垃圾回收补充行 13
垃圾回收补充行 14
垃圾回收补充行 15
垃圾回收补充行 16
垃圾回收补充行 17
垃圾回收补充行 18
垃圾回收补充行 19
垃圾回收补充行 20