JavaScript内存泄漏排查用Performance快照对比法:先拍三张快照(基线、操作后、重复操作后),再用Comparison视图查新增未删对象,顺Retainers链定位持有者,最后验证修复。

JavaScript 中用 Performance 内存快照对比法找内存泄漏,核心是:在关键操作前后手动拍下堆内存快照(Heap Snapshot),再逐层比对对象数量与引用链变化,定位持续增长且不该存在的对象。
一、打开 DevTools 并录制三张快照
在 Chrome 或 Edge 中打开开发者工具 → 切到 Memory 面板 → 选择 Heap snapshot → 点击左上角录制按钮(? 图标)。
- 第一次快照:页面加载完成、初始状态稳定后立即拍摄(Baseline)
- 第二次快照:执行疑似引发泄漏的操作(如打开弹窗、切换路由、反复渲染列表)后拍摄
- 第三次快照:重复同样操作 2–3 次后再拍摄(确认是否持续增长)
二、用“Comparison”视图查增长对象
在快照列表中,选中第二张或第三张快照 → 右上角下拉菜单切换为 Comparison → 左侧选择第一张作为参照。
- 重点关注 # New(新增数)和 # Deleted(已删数)列:若某构造函数的 # New − # Deleted 值明显为正且随操作次数递增,就是高危候选
- 常见泄漏信号:大量 Closure、Array、Object、自定义类(如
Chart、Modal)持续不回收 - 点击行左侧三角展开,看具体实例 —— 注意 Retained Size 大且 Distance 小(说明离 GC 根近,难被回收)
三、顺引用链(Retainers)追根溯源
选中一个可疑对象实例 → 右侧面板切换到 Retainers 标签 → 查看它被谁持有(即谁阻止它被回收)。
立即学习“Java免费学习笔记(深入)”;
- 重点看顶部几层:常见泄漏持有者包括 window、global、timer(setInterval/setTimeout)、event listener、闭包中的外层变量、未清理的 Map/Set 缓存
- 若看到 Closure 持有大量数据,点进去看其作用域(Scope)里有哪些变量被意外捕获(比如本该销毁的 DOM 节点、大数组被闭包长期引用)
- 若发现 Detached DOM tree,说明 DOM 节点已从文档移除但仍有 JS 引用(如事件监听器、jQuery.data、React ref 未清)
四、验证修复 & 避免误判
找到嫌疑代码后修改(如清除定时器、移除监听器、置空引用、用 WeakMap 替代 Map),再重复“操作 → 拍照 → 对比”流程验证。
- 避免把短期缓存误判为泄漏:可多操作几次,观察增长是否线性累积;真正泄漏会越积越多,缓存通常趋于稳定
- 注意快照时机:确保 JS 主线程空闲、无 pending promise、无正在运行的动画帧,否则可能拍到临时对象
- 配合 Allocation instrumentation on timeline(内存分配时间线)可辅助判断对象在哪段代码中高频分配
不复杂但容易忽略的是:泄漏往往不在“创建处”,而在“忘记清理处”。快照对比不是终点,而是把模糊怀疑变成可追踪的引用路径。


















