闭包泄漏源于无意中长期持有 DOM 元素、大数组等对象,阻碍垃圾回收;需用 Chrome Memory 面板拍快照对比,查 Closure 数量、Retained Size 及 Retainers,再结合 Performance 面板和人工审查高风险代码模式定位问题。

闭包本身不是问题,问题在于它无意中长期持有 DOM 元素、大数组、定时器、事件监听器或组件实例等对象,让这些对象无法被垃圾回收。排查核心就一件事:确认“谁还引用着它”,并找到那个不该存在的强引用链。
用 Chrome Memory 面板拍快照对比
打开 DevTools → Memory 面板,按三步操作:
- 先点 Take heap snapshot 拍一张基线快照
- 执行疑似泄漏的操作(比如打开/关闭弹窗、切换 Tab、重复渲染列表)
- 再拍一张快照,切换到 Comparison 视图,筛选 Constructor 为 Closure 的项
重点关注:
- 同名闭包数量持续增加(如
(closure) handleScroll出现 6 次且不减少) - 单个 Closure 的 Retained Size 明显偏大(例如 >300KB)
-
Retainers 列中出现
window、setInterval、EventListener或标着 detached 的 DOM 元素(如HTMLDivElement)
点开可疑闭包查捕获变量
在 Comparison 视图中双击高危 Closure,展开它的 Scope 或 Closure Context,看它实际捕获了哪些变量:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 是否捕获了整棵
document.getElementById('app'),而你其实只用了.textContent - 是否保留了一个未销毁的 React 组件
this或 Vue 实例 - 是否引用了
new Array(1e6)这类大数组,或缓存 Map 中的完整响应数据 - 是否把整个
state对象传进闭包,而不是解构出需要的几个字段
结合 Performance 面板看内存趋势
切换到 Performance 面板,勾选 Memory,录制用户操作:
- 如果每次操作后 JS Heap 曲线都阶梯式上升、不回落,基本可判定存在泄漏
- 点击内存峰值处的火焰图,能定位到触发泄漏的具体函数调用栈
- 开启 Allocation instrumentation on timeline,观察某次交互后是否有大量本该短命的闭包持续存活
人工审查高风险代码模式
不用等线上出问题,日常写代码时就该警惕这几类结构:
- 把函数赋给全局变量或模块顶层变量,且该函数引用了局部大对象
- 用匿名函数绑定事件:
el.addEventListener('click', () => { ... })→ 无法 remove -
setInterval(() => console.log(this.data), 1000)在组件卸载后仍运行 - 返回的闭包直接用了整个
props或state,没做精简

















