Retainers面板可直接揭示对象未被回收的原因,即谁在引用它及引用链是否合理;需先用隐身窗口拍两次堆快照(操作前后),再通过Comparison视图按#Delta降序定位Detached节点、Closure等可疑项,最后在Retainers中自下而上分析从GC Root出发的保留路径。

直接看 Retainers 面板,就能知道一个对象为什么没被回收——它被谁“拽着”不放。关键不是对象有多大,而是谁在引用它、这条引用链是否合理。
打开并生成有效的堆快照
先确保环境干净:用隐身窗口打开页面,禁用所有扩展。按 F12 打开 DevTools,切到 Memory 面板,选中 Heap Snapshot,点击 Take snapshot。建议至少拍两次:一次操作前(Baseline),一次反复触发疑似泄漏行为后(如打开/关闭模态框 5 次),中间手动点垃圾桶图标触发 GC。
定位可疑对象:从 Comparison 视图入手
切换到 Comparison 模式,选择前后两个快照对比。按 # Delta 降序排列,重点关注数量或内存增长明显、且 Retained Size 较大的条目。常见线索包括:
- Detached HTMLDivElement(或其它 Detached 节点):说明 DOM 已从页面移除,但 JS 仍持有引用
- Closure:闭包可能意外捕获了大数组、缓存或整个组件实例
- Array 或 Object 的 Retained Size 异常高(比如几 MB):很可能是缓存未清理或监听器未解绑
深入 Retainers 面板:读懂保留路径
点击某个可疑对象,在右侧面板中切换到 Retainers。这里展示的是“谁在引用它”,结构是自下而上:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
- 最底部是 GC Root(如
window、global、定时器回调、事件监听队列) - cacheMap、未销毁的类实例、
setInterval的闭包上下文) - 顶部是你选中的目标对象
重点检查中间那几层:是否存在本该释放却仍活跃的引用?例如,一个已卸载的 React 组件实例,仍被某个全局 eventBus.on() 回调闭包持有;或一个已 removeChild 的节点,被某处变量 lastClickedNode 长期引用。
结合 Dominators 视图辅助判断影响范围
切换到 Dominators 视图,它显示每个对象“支配”哪些其他对象(即如果它被释放,哪些对象也能被回收)。展开高 Retained Size 的节点,观察其子树是否包含大量 Detached 节点或 Closure 实例。若一个闭包的 Retained Size 占总堆 30%,而它只服务于一个已隐藏的面板,基本可确认为泄漏源头。
真正卡点不在工具本身,而在理解引用链是否必要。看到 window → timer → closure → hugeArray 这样的路径,就该回头检查定时器是否 clearTimeout,闭包是否该重构为无状态函数。

















