在 Chrome DevTools Heap Profiler 中分析闭包需先捕获堆快照,再筛选 closure 构造器对象,展开 Retainer Tree 查看引用路径,结合源码定位泄漏源头(如未清除的定时器或事件监听器),最后通过垃圾回收和新快照验证修复效果。

在 Chrome DevTools 的 Heap Profiler 中查看闭包的 Retainer Tree,核心是:**先捕获堆快照,再定位闭包对象,然后展开其保留者链(Retainer Tree)**。闭包本身不会直接标为“Closure”,而是以 closure 类型出现在构造函数名一栏,且通常被外层函数作用域或全局变量等保留。
1. 捕获堆快照并筛选闭包对象
打开 DevTools → Memory 面板 → 选择 “Heap snapshot” → 点击 “Take heap snapshot”。快照加载完成后:
- 在左上角搜索框输入
closure(注意小写),可快速过滤出所有闭包实例; - 也可切换到 “Constructor” 视图,找到
closure构造器(不是 Closure,没有大写 C),点击查看详情; - 重点关注那些 size 较大、Shallow Size 小但 Retained Size 大的对象——这往往是被意外保留的闭包。
2. 展开 Retainer Tree 查看谁在持有它
选中一个 closure 对象后,右侧面板默认显示 “Retainers” 标签页(若没看到,手动点一下):
- 这里展示的是从 GC root 到该闭包的完整引用路径,即 Retainer Tree;
- 每行是一个保留者(retainer),箭头方向表示“被谁引用”,例如:
Window → app → timer → closure表示闭包被 timer 对象的某个属性引用; - 关键看路径中是否有本该被释放却仍存活的中间对象(如未清除的事件监听器、全局缓存、定时器回调等)。
3. 结合代码确认闭包泄漏源头
Retainer Tree 只告诉你“谁留着它”,不直接说明“为什么不该留”。需对照源码分析:
- 检查路径中每个对象的定义位置(右键 → “Reveal in Sources” 或看 “@” 后的文件行号);
- 特别留意:
setTimeout/setInterval回调、事件监听器(addEventListener)、对象属性赋值(如obj.handler = function() {...})、模块级变量缓存; - 常见陷阱:闭包捕获了大型 DOM 元素或数据结构,而闭包又被长期存活对象(如全局对象、单例)间接持有。
4. 验证修复是否生效
改完代码后别只看 Retainer Tree,要验证内存是否真正释放:
- 触发预期的清理逻辑(如移除监听器、清除定时器、置空引用);
- 手动触发垃圾回收(DevTools Memory 面板点击 “Collect garbage” 图标);
- 再拍一次快照,搜索相同 closure,确认它已消失或 Retained Size 显著下降。
不复杂但容易忽略:闭包的 Retainer Tree 不是静态快照,它反映的是某一时刻的引用关系。确保在复现问题场景后立即捕获,否则可能错过关键保留链。


















