流程本身没毛病,补两个提速手段:`queryObjects()` 直接数实例,以及 Retainers 面板要「从 GC Root 往下读」而不是从对象往上读。

Retainers 的正确读法:面板里那条链默认给的是到 GC Root 的最短路径,顺序是从「离对象最近的引用者」往上排。实战别一层层往上点,直接展开找第一个属于你自己项目的帧(带文件名+行号),那个引用者就是元凶。如果整条链全是 React/Vue 内部帧,那基本是组件卸载时副作用没清,去查 `useEffect` 的 cleanup 返回、`onUnmounted`,或者事件总线订阅忘了取消。

比拍三张快照更快的办法——queryObjects:Console 里敲 `queryObjects(YourClass.prototype)` 回车,返回该类所有存活实例的数组,`.length` 就是泄漏计数。反复操作一次就数一遍,数字只涨不跌就是它。前提是构造函数能在当前作用域访问到,全局访问不到就临时挂一下 `window`。这个比「操作 10 次 → GC → 拍快照 → 对比」快一个数量级,适合先粗筛。

你列的四种之外,项目里更高频的泄漏源:`ResizeObserver` / `IntersectionObserver` / `MutationObserver` 没 `disconnect()`;`requestAnimationFrame` 递归没取消;Map/Set 当缓存只 set 不 delete(尤其拿 DOM 节点当 key);axios 请求没 abort;还有图片 `URL.createObjectURL` 没 revoke。

另外长列表页面拍快照容易卡死,可以改用 Allocation sampling,采样方式对性能影响小,能看分配调用栈,虽然计数不精确但找「谁在疯狂分配」够用了。

最后一个坑:Heap snapshot 文件动辄几百 MB,里面包含页面全部字符串,包括 token 和用户数据。排查完删掉,别随手发群里或传网盘。还有手动 `Collect garbage` 是一次性强制回收,别据此判断「线上应该也能回收」——线上的 GC 触发时机你控制不了。