0%

JavaScript 垃圾回收

内存管理

JavaScript 自动垃圾回收。

引用计数

对象引用计数为0时回收。

1
2
let obj = { name: 'Alice' }
obj = null // 回收

循环引用问题

1
2
3
4
5
6
7
let obj1 = {}
let obj2 = {}
obj1.ref = obj2
obj2.ref = obj1
obj1 = null
obj2 = null
// 现代引擎能处理

标记清除

主流算法。

  1. 标记根可达对象
  2. 清除未标记对象

内存泄漏

  • 全局变量
  • 闭包
  • DOM 引用
  • 定时器

优化

  • 避免全局变量
  • 及时清除引用
  • 使用 WeakMap/WeakSet

总结

JavaScript 的垃圾回收机制自动管理内存,最常见的是标记-清除算法。深入理解 GC 有助于写出内存高效的程序,并避免性能陷阱。

垃圾回收算法

标记-清除 (Mark-and-Sweep)

  1. 从根对象开始标记可达对象
  2. 清除未被标记的对象

引用计数 (Reference Counting)

为每个对象维护一个引用计数;计数为0时回收。存在循环引用问题。

分代回收 (Generational GC)

对象根据存活时间分代,新生代回收频繁,老生代回收较少。

增量回收与并行回收

现代浏览器支持将 GC 工作拆分成小块并在后台线程执行,减少停顿时间。

内存管理技巧

  • 避免建立大规模长生命周期对象
  • 使用 const 避免意外重新赋值
  • 对 DOM 对象使用 WeakMap 保存元数据

WeakMap/WeakSet 的意义

WeakMap 的键是弱引用,垃圾回收不会因为键存在而阻止其回收:

1
2
3
4
let wm = new WeakMap();
let obj = {};
wm.set(obj, 'meta');
obj = null; // 键对象可以被回收

诊断工具

  • 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