闭包缓存累积表现为Closure对象数量异常增长、Retained Size持续偏高,与反复操作强相关,本质是“缓存逻辑+闭包引用+缺乏淘汰”三者叠加;需通过堆快照筛选closure、查Retainer链、比对Detached DOM及验证清理效果来定位。

闭包缓存累积在内存排查中主要表现为 Closure 对象数量异常增长、Retained Size 持续偏高,且与业务操作(如反复打开关闭模块、切换路由)强相关。它不是孤立现象,而是“缓存逻辑 + 闭包引用 + 缺乏淘汰”三者叠加的结果。
看堆快照里 Closure 的重复性与 Retained Size
在 Chrome Memory 面板拍下 Heap Snapshot 后,用 Class Filter 筛选 (closure):
- 关注同名闭包高频出现(如
cacheHandler@util.js:42出现 50+ 次),尤其在多次触发缓存写入操作后数量线性上升; - 单个闭包的 Retained Size 明显大于 Shallow Size(比如 Shallow 只有 128B,Retained 却达 8MB),说明它拖住了大量外部数据(如缓存的 JSON、Canvas ImageData、DOM 节点树);
- 点击某个闭包 → 展开 ClosureScope → 查看捕获的变量:若发现
cacheMap、resultStore或类似命名的对象,且其类型为 Object/Map/Array,值体积大,基本可判定是缓存闭包。
查 Retainer 链确认缓存持有者
闭包本身不危险,危险的是谁一直留着它。右键闭包 → “Reveal in Summary view” → 点开 “Retainers” 标签页:
- 若上级引用指向
window.cachePool、MyModule.CACHE或某个长期存活 class 实例的属性(如this._handlers),说明缓存结构未做生命周期管理; - 若看到
setInterval或addEventListener引用链穿过闭包,说明缓存回调被定时器或监听器长期持有着; - 若多个闭包共享同一 Retainer(如都挂在同一个 Map 实例下),说明缓存容器本身没做容量控制或过期清理。
比对操作前后快照中的 Detached DOM + Closure 关联
很多缓存闭包实际是为了“记住 DOM 状态”,但 DOM 已卸载,闭包还在:
立即学习“前端免费学习笔记(深入)”;
- 在 Comparison 视图中筛选 “Detached DOM tree”,再点开任一 Detached 节点 → 查看 “Retained by” 链路;
- 若路径中出现闭包(如
renderCallback@list.js:88→componentCache),说明该闭包仍在引用已移除的 DOM,而缓存又没失效,形成双重滞留; - 这类问题在 SPA 中高频复现:用户快速切页 5 次,快照里 Detached DOM 数量 + Closure 数量同步涨了 5 倍,且 Retained Size 不降。
验证缓存是否真该存在
不能只看“有”,要看“该不该有”:
- 手动调用缓存清理函数(如
clearCache()或cache.evictAll())后重拍快照,观察对应 Closure 是否消失、Retained Size 是否回落; - 在控制台执行
console.log(cache.size)或cache.keys(),确认缓存项数量是否随操作无限制增长; - 配合 Allocation instrumentation on timeline:录制一段操作,过滤出频繁分配的 Closure 构造位置,定位到具体哪行
new Map()或function() { ... }在不断生成新缓存闭包。


















