JS 的垃圾回收机制
1. 回收机制简介
JS 垃圾回收机制很简单:找出不再使用的变量,释放掉其占用的内存。但这个过程不是实时的——因为开销较大,垃圾回收系统(GC)会按照固定的时间间隔周期性地执行。
通常有两种实现方式:标记清除和引用计数。引用计数不太常用,标记清除较为常用。
2. 标记清除(Mark and Sweep)
JS 最常用的 GC 方式。
当变量进入环境时(例如在函数中声明一个变量),就将这个变量标记为"进入环境"。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应环境就可能会用到它们。当变量离开环境时,将其标记为"离开环境"。
function test() {
var a = 10; // 进入环境
var b = 20; // 进入环境
}
test(); // 执行完毕后 a、b 被标记离开环境,被回收
3. 引用计数(Reference Counting)
跟踪记录每个值被引用的次数。当一个引用类型值被赋给变量时,引用次数为 1;赋给另一个变量加 1;引用变量取其他值减 1;引用次数为 0 时可被回收。
function test() {
var a = {}; // a 引用次数为 0
var b = a; // a 引用次数 +1 = 1
var c = a; // a 引用次数 +1 = 2
var b = {}; // a 引用次数 -1 = 1
}
缺陷:循环引用会导致内存无法回收(IE 早期 COM 对象问题)。现代引擎(V8)已弃用引用计数。
4. 如何分析内存使用情况
Chrome DevTools 提供 Memory / Performance 工具:
- Memory 面板的 Heap snapshot:对 JS 运行时内存做快照并比较不同时间点的对象数量增长。
- Performance 面板:观察 JS Heap 曲线是否单调上升。
每个结果视图提供:
- summary 列表:按类型展示对象与合计大小(
shallow size:类型所有对象总和;retained size:加上保留此对象的其他对象大小)。 - comparison 视图:对比不同快照,对查找内存泄漏非常有用。
5. 怎样避免内存泄漏
- 减少不必要的全局变量,及时对无用的数据进行垃圾回收(变量用完置
null)。 - 注意程序逻辑,避免"死循环" / 长期持有的引用。
- 避免创建过多对象,原则:"不用了的东西要及时归还"。
- 清除定时器 / 事件监听器:组件销毁时调用
clearInterval、removeEventListener。 - 避免意外闭包:不要让闭包长期持有 DOM / 外部对象引用。
来源整理自:我的有道云笔记



