排查JS内存泄漏需拍三张逻辑关联快照:刷新后GC拍基线(snapshot-0),执行一次操作闭环后GC拍snapshot-1,重复2–3次后GC拍snapshot-2;在Comparison视图中对比snapshot-2与snapshot-0,重点关注Δ>0且递增的Constructor、Retained Size增长而Shallow Size不变、Detached对象持续存在三类异常;双击可疑构造函数查看Retainers引用链,从下往上定位本该销毁却仍活跃的持有者;配合Allocation Timeline和Performance面板验证泄漏。

用 Chrome DevTools 分析内存快照排查 JS 内存泄漏,核心是“拍得准、比得清、追得深”。不是堆快照越多越好,而是三张有逻辑关系的快照配合手动垃圾回收(GC),再聚焦构造函数变化和引用链源头。
拍三张关键快照并确保干净基线
别一加载完就点“Take Snapshot”。真实有效的对比依赖状态可控:
- 刷新页面,等资源加载完毕、无动画、无定时器运行;点击 Memory 面板左上角垃圾桶图标(Collect garbage),再拍第一张——这是干净的基线快照(snapshot-0)
- 执行一次完整操作闭环(如打开弹窗 → 点确定 → 关闭弹窗),等待 2–3 秒让异步逻辑结束,再次点垃圾桶,拍第二张(snapshot-1)
- 重复同样操作 2–3 次,再次 GC,拍第三张(snapshot-2)。只有持续增长,才说明对象“只增不减”
在 Comparison 视图里盯住三类异常信号
选中 snapshot-2 → 右上角下拉菜单切换为 “Comparison” → 左侧选择 snapshot-0 作参照。重点关注:
-
Δ > 0 且逐次上升的 Constructor:比如
(closure)、Detached HTMLDivElement、ChartInstance、UserInfo——这些不是“新增”,而是“该收没收” - Retained Size 明显增长但 Shallow Size 几乎不变:说明对象本身小,却拖着大片内存(典型如闭包捕获了整个组件实例或大数组)
-
Detached 对象反复出现且 Δ 稳定为正:不只是浏览器 DOM,Node.js 中的
Buffer、EventEmitter、pendingRequests也会被标为 Detached,往往是泄漏入口
顺着 Retainers 找到强引用源头
双击某条高 Δ 的构造函数(如 (closure) 或 Detached HTMLDivElement),右侧打开 Retainers 标签页,从下往上读引用链:
立即学习“Java免费学习笔记(深入)”;
- 最底下是你选中的对象,往上是直接持有者,再往上是它的持有者……直到顶层 GC Root(如
window、document、定时器回调) - 重点不是链有多长,而是中间哪一环本该销毁却还活跃:比如已卸载的 React 组件仍被
eventBus回调持有;removeChild后的节点还被变量lastClickedNode引用;window.timerRef指向一个没clearTimeout的定时器 - 右键某行 → “Reveal in Summary view”,跳过去查同类对象总实例数,确认是否越积越多
配合 Allocation Timeline 和手动 GC 验证
快照是静态切片,需动态行为佐证:
- 开启 “Record allocation stack traces”(设置齿轮图标 → 勾选),能直接看到对象是在哪行代码
new出来的 - 用 Performance 面板录制操作过程,观察内存曲线是否阶梯式上升
- 每次拍完快照后,务必手动点垃圾桶再拍一张。如果某类对象在 GC 后仍不减少,且随操作稳定增长,基本可判定为泄漏


















