detached dom节点泄漏需通过对比堆快照识别:先gc后拍基准快照,执行操作再gc拍对比快照,在comparison中筛选delta>0的“detached dom tree”,结合retainers定位引用源,最后用gc后快照验证是否真实泄漏。

Detached DOM 节点是前端内存泄漏中最常见、也最容易被忽视的一类。它指 DOM 元素已从文档树中移除(比如用 remove() 或 innerHTML = ''),但 JavaScript 仍通过变量、闭包、事件监听器或缓存等方式持有对它的引用,导致浏览器无法回收其内存。
拍两份快照做对比才是关键
单张堆快照看不出问题——因为 Detached 节点本身就在“可访问对象”中(JS 还能读到它)。必须靠对比:
- 先让页面空闲几秒,手动点 DevTools Memory 面板的「垃圾回收」图标(垃圾桶),再拍第一张快照,命名为「基准快照」
- 执行疑似泄漏操作(例如:打开弹窗 → 关闭弹窗,重复 3~5 次;或切换路由进入/退出某组件)
- 再次 GC,再拍第二张快照,命名为「操作后快照」
- 选中第二张快照 → 切换到「Comparison」视图 → 左上角下拉选择「基准快照」作为对比源
在 Comparison 视图里盯紧这三列
重点关注筛选结果中 Delta > 0 且数值明显增长的项:
- Constructor 名为 “Detached DOM tree”:这是最直接信号。如果 Delta 是 +12、+36、+60,说明每次操作都新增了未释放的分离节点
-
Distance 较大但 Retained Size 很高:比如某个
div的 Retained Size 达到 2.4MB,说明它连带持有了大量子节点或绑定数据 -
点击该行 → 右侧看 Retainers 引用链:常见锚点包括:
Window(全局变量缓存)、Closure(闭包里存着 node)、EventListener(监听器没 off)、Array或Map(缓存容器未清空)
顺着引用链定位具体代码位置
Retainers 面板会列出“谁在引用这个 Detached 节点”。逐层向上点开,直到看到你写的代码文件和行号:
- 若看到
global > myCache→ 检查全局数组或 Map 是否在组件销毁时清空 - 若看到
Closure > initHandler > handler→ 找到对应事件绑定处,确认是否调用了removeEventListener - 若看到
Element > __data__或 jQuery 的$.cache→ 说明用了旧版 jQuery 或未正确销毁插件实例
验证是否真泄漏:GC 后再拍一次快照
别只看数字涨了就下结论。真实泄漏的表现是:强制 GC 后,Detached 节点数量不回落:
- 拍完「操作后快照」后,立刻点垃圾桶图标触发 GC
- 等几秒,再拍第三张快照(「GC 后快照」)
- 用「GC 后快照」和「基准快照」再比一次 —— 如果 Detached DOM 的 Delta 依然显著为正,基本可以确认泄漏











