内存快照对比是定位javascript内存泄漏最直接有效的方法:先在空闲状态拍“before”快照,再执行疑似泄漏操作并触发gc后拍“after”快照,通过comparison模式筛选# new > 0且size delta > 0的对象,结合retaining path分析全局变量、未移除监听器、未清除定时器、残留dom引用等典型泄漏源。

在 JavaScript 内存泄漏排查中,内存快照对比是定位残留对象最直接有效的方法。核心思路是:在可复现的疑似泄漏操作前后分别采集堆快照(Heap Snapshot),通过比对两次快照中对象数量和引用链的变化,识别出本该被回收却持续存活的对象。
如何正确采集对比快照
打开 Chrome DevTools → Memory 面板 → 选择 “Heap snapshot” → 点击 “Take heap snapshot”:
- 第一步(基准快照):确保页面处于稳定空闲状态(无动画、无定时器活跃、无异步回调待执行),执行一次快照并标记为 “Before”
- 第二步(操作快照):执行一次完整的疑似泄漏操作(如打开又关闭一个模块、切换路由、增删组件等),等待几秒让垃圾回收自然发生(也可手动点击 “Collect garbage” 图标触发 GC),再拍一次快照,标记为 “After”
- 第三步(对比快照):在快照列表中选中 “After”,顶部下拉选择 “Comparison”,再选中 “Before” —— 此时视图自动切换为差异模式,只显示新增或仍存活的对象
重点关注“新增对象”和“Shallow Size 不为 0”的节点
对比视图中,Constructor 列显示对象构造函数名,# New 列显示本次快照比上一次新增的实例数,Size Delta 显示内存变化量:
- 优先筛选 # New > 0 且 Size Delta > 0 的条目,尤其是反复操作后持续增长的类(如
MyComponent、EventEmitter、闭包函数、大型数组等) - 点击展开某构造函数,查看右侧 “Objects” 列中的具体实例;鼠标悬停实例会显示其保留路径(Retaining Path)—— 这是关键!它告诉你谁在强引用这个对象,阻止了 GC
- 注意 Shallow Size 不为 0 的对象(比如一个未销毁的定时器函数),即使它自身不大,但可能持有大量子对象(Retained Size 很大)
识别典型泄漏模式的保留路径
从 Retaining Path 中常能快速判断泄漏根源:
-
全局变量/意外闭包引用:路径以
window、globalThis或某个长期存活对象(如appStore)开头 → 检查是否把局部对象赋值给了全局变量,或事件监听器/回调中意外捕获了外部作用域 -
未移除的事件监听器:路径中出现
EventListener→target→someDOMElement→ 查看监听器绑定的回调是否引用了已卸载组件的this或闭包变量 -
定时器未清除:路径含
setTimeout/setInterval→ 回调函数 → 组件实例 → 检查组件销毁时是否调用了clearTimeout - DOM 引用未清理:路径指向已从文档移除但仍被 JS 变量引用的 DOM 节点 → 检查缓存、模板引用、第三方库(如图表库)是否遗留了对旧节点的引用
辅助技巧提升排查效率
单靠快照对比有时信息过载,配合以下操作更精准:
- 使用右上角搜索框输入构造函数名(如
MyModal)或关键词(如onScroll),快速过滤目标对象 - 在对比视图中右键某对象 → “Reveal in Summary view” → 回到摘要视图定位上下文
- 多次重复“操作 → GC → 快照”,观察同一构造函数的
# New是否线性增长(如每次+1)→ 若是,基本确认存在泄漏 - 结合 Performance 面板录制操作过程,确认是否存在未结束的 JS 执行、频繁重绘或长任务干扰 GC
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











