最有效的方式是拍三张配合手动GC的堆快照并用Comparison视图分析:先拍基线快照,再执行疑似泄漏操作并GC后拍第二、第三张;重点观察Δ>0且持续上升的构造函数、Retained Size增长但Shallow Size不变、Detached对象反复出现三类信号;双击高Δ构造函数查看Retainers引用链,识别window/document/全局Map/未清除定时器等不应存在的持有者;必要时切Dominators找真正阻塞GC的根因。

最有效的方式是拍三张有明确意图的堆快照,再用 Comparison 视图对比增长对象及其引用链。关键不是看谁最大,而是看谁“只增不减”——那些操作后没被回收的对象,才是泄漏的真凶。
拍三张有意义的快照
别在页面刚加载完就点“Take Snapshot”。必须配合手动垃圾回收(GC)和可控操作:
- 刷新页面 → 等加载完成、无交互 → 点击小垃圾桶图标(Collect garbage)→ 拍第一张:基线快照(snapshot-0)
- 执行一次疑似泄漏的操作(如打开/关闭模态框、切换路由、渲染列表)→ 等 2–3 秒 → 再点 Collect garbage → 拍第二张(snapshot-1)
- 重复同样操作 2–3 次 → GC → 拍第三张(snapshot-2)
在 Comparison 视图盯住三类信号
选中 snapshot-2 → 右键 → Compare to previous snapshot,重点关注:
- Constructor 列中 Δ > 0 且持续上升的类型:比如 Closure、UserInfo、ChartInstance,或 Detached HTMLDivElement —— 这些不是“新增”,而是“该收没收”
- Retained Size 明显增长但 Shallow Size 几乎不变:说明对象本身小,却拖着大片内存(典型如闭包捕获了整个组件实例)
- Detached 对象反复出现且 Δ 稳定为正:不只是浏览器 DOM,Node.js 中的 Buffer、EventEmitter、pendingRequests 也会被标为 Detached,往往是泄漏入口
点进去看 Retainers,找不该存在的引用
双击高 Δ 的构造函数(如 Closure),右侧打开 Retainers 标签页,从上往下读引用链:
立即学习“Java免费学习笔记(深入)”;
- 如果看到 window、document、全局 Map 或未清除的定时器回调持有它,而对应逻辑早已结束,大概率就是泄漏点
- 常见模式:
addEventListener绑在 document 上却没remove;setInterval回调里闭包捕获大数组且没clearInterval;模块顶层缓存 Map 的 key 是 request 对象,没设 TTL - 别只看 Distance 值,重点看路径中是否存在本该销毁却仍活跃的上下文(比如已卸载的 React 组件、Vue 实例)
必要时切 Dominators 查支配源头
当 Retainers 链太深、干扰多时,可切换到 Dominators 标签页:
- Dominators 显示的是“谁真正挡住了 GC”——即某个对象若被释放,能直接让哪些其他对象也被释放
- 找到 Retained Size 最大的几个 dominator,它们往往就是泄漏的根因(例如一个未清理的全局 eventBus、一个长期存活的缓存容器)
- 结合代码确认:这个 dominator 是否本应在某次操作后被显式销毁或清空?


















