Vue内存泄漏主因是组件卸载时未手动清理全局资源。需清除定时器、解绑事件监听器、调用第三方库destroy方法、合理管理effectScope与keep-alive组件生命周期,并避免响应式数据意外挂载全局。

Vue 应用中的内存泄漏,核心在于“组件该销毁时没真正销毁”。Vue 本身会自动清理响应式依赖和内部 effect,但对开发者手动创建的全局资源无能为力——这些才是泄漏主因。关键不是“有没有写错”,而是“有没有主动断开引用链”。
未清除的定时器和异步任务
setInterval、setTimeout、Promise.then、async/await 回调都可能形成闭包,隐式持有组件实例或 ref 数据。
- 定时器必须在 onUnmounted(Vue 3)或 beforeUnmount 中显式清除,不能只靠组件卸载自动释放
- Promise 链中避免在 .then 里直接修改组件响应式状态;若请求已发出但组件已销毁,应通过 abortController 或标志位丢弃结果
- 使用 effectScope 管理副作用时,记得调用 scope.stop(),尤其在动态创建 effect 的场景下
未解绑的事件监听器
全局事件(window、document)、自定义事件总线(eventBus)、第三方库绑定的 DOM 事件,一旦注册却未注销,就会让组件实例持续被引用。
- 所有 addEventListener 都要配对 removeEventListener,且监听函数不能是匿名函数或箭头函数(无法精确移除)
- 使用 Composition API 时,推荐用 useEventListener(VueUse 提供)这类封装,它会在组件卸载时自动解绑
- eventBus.$on 必须对应 $off;更推荐改用 provide/inject 或 Pinia store 的订阅机制,避免全局强引用
第三方库未正确销毁
ECharts、Mapbox、Three.js、PDF.js 等重型库常自行管理 DOM、Canvas、WebGL 上下文和内部定时器,不调用 destroy 方法会导致整块内存滞留。
立即学习“前端免费学习笔记(深入)”;
- 初始化后务必保存实例引用(如 this.chart = new Chart(...)),并在 onUnmounted 中调用 chart.destroy()
- 注意某些库的 destroy 方法是异步的(如某些地图 SDK),需 await 确保完成后再离开
- 避免在 setup 中直接 new 实例并丢弃引用;若需复用,考虑用 provide 注入或缓存到顶层 store,但要控制生命周期
keep-alive 与响应式数据残留
keep-alive 缓存组件不会触发 unmounted,但其中的定时器、监听器、大型数据仍可能持续占用资源;同时,Pinia/Vuex 中意外保留的大对象也会阻碍 GC。
- 对 keep-alive 组件,用 onActivated / onDeactivated 替代 mounted/unmounted 处理资源启停
- Pinia store 中避免直接赋值大型数组或嵌套对象;改用 ID 引用 + 缓存策略,必要时在 onUnmounted 中调用 store.$reset()
- 检查 reactive 对象是否无意中被挂到 window 或其他全局变量上;ref 值也不要长期存于闭包外的静态 Map 中


















