判断spa内存泄漏最直观信号是gc后内存“该降不降”:若每次gc回落幅度递减甚至不降,说明对象被意外持有;结合performance面板内存曲线、allocation追踪和heap snapshot对比,可定位vuecomponent等未销毁对象及全局事件监听器、定时器等常见泄漏源。

直接看内存曲线是否“该降不降”——这是判断大型 SPA 是否存在内存泄漏最直观的信号。重点不是总内存多高,而是垃圾回收(GC)发生后,内存有没有明显回落。如果每次 GC 后释放量越来越少,甚至几乎不回落,那大概率有对象被意外持有,无法释放。
打开 Chrome DevTools 的 Performance 面板做录制
在页面完成关键交互(比如路由跳转、列表滚动、模态框反复打开关闭)后,点击录制按钮,持续 20–30 秒。结束后查看时间轴中的“Memory”轨道:
- 横轴是时间,纵轴是 JS 堆内存(JS Heap)使用量,蓝色实线就是实时占用曲线
- 灰色竖线代表一次垃圾回收事件,对应位置应看到明显的内存下降
- 若曲线呈单调上升趋势,且灰色竖线处回落幅度越来越小(例如从降 30MB 缩到只降 5MB),说明可回收对象在减少,泄漏正在累积
结合 Allocation instrumentation on timeline 捕获分配源头
在 Performance 面板设置中勾选 “Allocation instrumentation on timeline”,重新录制。该模式能标记出每块新分配内存对应的调用栈:
- 播放录制结果时,把鼠标悬停在内存上升段,下方会显示“Allocations”子轨道
- 点开某一段高亮区域,右侧 Summary 标签页列出新增对象最多的构造函数(如 VueComponent、ReactElement、闭包函数名)
- 重点关注那些在用户离开页面后仍持续出现的构造函数——它们很可能没被销毁,比如未解绑的全局事件监听器、未清除的定时器、或组件内保留的 DOM 引用
用 Memory 面板拍快照对比对象留存情况
在关键操作前后(例如进入某页 → 执行操作 → 离开该页)分别拍三张堆快照(Heap Snapshot):
- 切换到 Memory 面板,选 “Heap snapshot”,点击 Capture
- 第一张:空闲状态;第二张:操作完成后立即拍;第三张:离开页面并等待几秒后拍
- 用第二张减去第一张,看哪些对象数量激增;再用第三张减去第二张,看哪些对象“本该消失却还在”
- 特别关注 Retained Size 大、Distance 小的对象,它们往往通过较短引用链连着 GC Roots(如 window、document、全局变量)
验证常见泄漏场景是否被触发
SPA 中高频泄漏点有固定模式,可针对性检查:
- 路由切换后,旧组件实例是否还挂在 $refs / refs 中,或被闭包捕获(如 setTimeout 回调里用了 this)
- 第三方库(如地图、图表)是否调用了 destroy() 或 remove(),而你只做了 unmount 却没清理底层资源
- 全局事件总线(如 mitt、EventBus)是否在组件卸载时忘记 off(),导致监听函数长期驻留
- 使用了 WeakMap / WeakSet 的地方是否误用了普通 Map / Set,让对象无法被自动释放










