支配者树是定位spa内存峰值异常最直接有效的视图,它揭示“谁卡住了释放”,关键在识别retained size高且位于支配树顶端的“控制节点”,而非单纯找最大对象。

支配者树(Dominator Tree)是定位单页应用(SPA)内存峰值异常最直接有效的视图。它不展示物理引用链,而是揭示“谁卡住了释放”——即若某个对象被回收,其支配的所有子对象将一并可被回收。真正导致内存峰值的,往往不是最大的单个对象,而是Retained Size高、且处于支配树顶端的“控制节点”。关键不在找“大”,而在找“总开关”。
聚焦Dominators视图的前三行
在 Chrome DevTools Memory 面板拍摄堆快照后,切换到 Dominators 标签页:
- 按 Retained Size 降序排列,优先看前3–5行,尤其是 Retained Size 占整份快照 5% 以上的条目
- 重点识别构造函数为
(closure)、Object、Array、或你项目中高频使用的类名(如DataTable、RouteCache、StoreInstance) - 跳过
window、globalThis、document这类顶层宿主对象——它们总是排第一,但问题一定藏在其某个属性里(比如window.__routerCache或document._eventHandlers)
验证支配者是否真凶:看保留树 + 对比实例数
双击可疑支配者行,右侧自动展开 Retaining tree(保留树):
- 逐层展开,确认它持有哪些子对象;特别留意是否持有大量已卸载组件的
this、未清理的Map/Set缓存、或 Detached DOM 节点 - 右键该对象 → Reveal in Summary view,跳转后点击对应 Constructor 名称,查看同类实例总数;若数量远超预期(如路由组件出现 20+ 实例却只应有 1 个活跃),基本可判定泄漏
- 对比操作前后快照:若某闭包的 Retained Size 从 2MB 涨到 18MB,而 Shallow Size 始终只有几 KB,说明它拖着越来越多的“亲戚”,是典型的闭包泄漏信号
识别 SPA 特有陷阱:框架组件与状态管理
单页应用中,支配者常伪装成框架内部对象,需穿透表象看归属:
-
React.Component或VueComponent出现在 Dominators 顶部?检查其 retaining tree 中是否存在未解绑的事件监听器、全局订阅(如 PubSub.on)、或定时器回调 -
Proxy、Observable、ReactiveState类型对象占比高?大概率是响应式系统因依赖追踪未清理,导致整个状态树无法释放 - 自定义 Hook(如
useCache、usePolling)返回的闭包频繁上榜?打开它捕获的外层变量,确认是否无意保留了路由参数、API 响应数据或 DOM 引用
交叉验证:结合时间线与 Detached DOM
支配者树给出的是静态快照中的“最大阻碍”,但要确认是否引发峰值,需动态佐证:
- 回到 Allocation instrumentation on timeline 模式,录制用户典型操作(如切换 Tab、刷新列表),观察内存曲线是否在操作后持续抬升不回落
- 在快照的 Summary 视图搜索
Detached DOM tree,若数量多且 Retained Size 高,说明 DOM 已移除但 JS 仍强引用;此时回到 Dominators 查找持有这些节点的 JS 对象(常见于data-属性缓存、第三方图表库的内部引用) - 对疑似泄漏点打日志:在组件
unmount或destroyed钩子中输出清理状态,再拍快照验证该对象是否真的从支配树中消失










