“可达”对象指从根对象(如全局对象、调用栈)出发沿引用链能遍历到的对象,“不可达”对象则无法被遍历到,GC仅回收后者;全局变量始终可达,局部对象在无外部引用时变为不可达;闭包、未解绑事件监听器、定时器、Map/Set未清理等易致内存泄漏;应设null、移除监听器、清理定时器、使用WeakMap/WeakRef;可通过堆快照、console.memory、window.gc()调试验证。

JavaScript中对象的生命周期由引用关系决定,垃圾回收器(GC)只回收那些不再被任何活跃引用指向的对象。理解引用如何建立、维持和断开,是掌握内存管理的关键。
什么是“可达”与“不可达”对象
引擎从一组根对象(如全局对象、当前执行函数的局部变量、调用栈中的值)出发,沿着引用链向下搜索。所有能被遍历到的对象称为“可达”,其余为“不可达”。GC只会清理不可达对象。
- 全局变量始终可达,除非显式赋值为null或重新声明
- 函数内部定义的局部对象,在函数返回后若无外部引用(如闭包捕获、事件监听器保存),即变为不可达
- DOM节点即使从文档中移除,只要JS变量仍持有其引用,就依然可达
常见导致意外内存泄漏的引用场景
并非所有引用都显而易见,以下情况容易让对象持续“存活”:
- 闭包隐式保留引用:内嵌函数访问外层函数变量时,整个外层作用域对象可能被长期持留
- 事件监听器未解绑:绑定到DOM元素的回调函数若引用了大对象(如缓存数据、整个组件实例),该对象无法被回收
- 定时器中的this绑定:使用setInterval且回调内引用了实例属性,即使组件已销毁,定时器仍在运行并阻止回收
- Map/Set等集合未清理:将对象作为键存入Map后忘记删除,即使原引用消失,Map仍持有强引用
如何主动管理引用以协助GC
JavaScript不提供手动释放内存的API,但可通过控制引用显式“断开连接”:
立即学习“Java免费学习笔记(深入)”;
- 不再需要的变量及时设为null(尤其对大数组、JSON解析结果、Canvas图像数据)
- 移除DOM节点前,用removeEventListener清除对应监听器;或使用AbortController统一控制
- 在类的销毁方法(如React的componentWillUnmount、Vue的beforeUnmount)中清理定时器、取消网络请求、清空缓存Map
- 对弱引用场景,使用WeakMap或WeakRef(配合deref()),它们不会阻止目标对象被回收
调试与验证引用状态的方法
可通过浏览器开发者工具观察实际回收行为:
- 在Memory面板中录制堆快照(Heap Snapshot),筛选构造函数名查找对象实例,查看其“Retainers”(保留者)确认哪些引用链阻止了回收
- 使用console.memory粗略监控JS堆大小变化
- 触发强制GC:在Console中执行window.gc()(仅Chrome DevTools启用--js-flags="--expose-gc"时可用)
- 留意“Detached DOM tree”警告——表示DOM节点已脱离文档但仍被JS引用


















