前端内存泄漏排查:一个定时器引发的血案

Cold 发布于 2023-08-14 17 次阅读 289 字 预计阅读时间: 1 分钟 前端开发


一个后台管理系统,用户反馈「开久了越来越卡,最后崩掉」。打开 Chrome 任务管理器,发现标签页内存从 200MB 一路涨到 2GB。

排查步骤

  1. DevTools → Memory → 拍快照
  2. 操作一段时间(切换路由、打开弹窗)
  3. 再拍快照,选 Comparison,看新增对象
  4. 发现大量 Detached DOM tree 和 Timer

定位到问题

有个实时刷新的组件,在 mounted 里 setInterval,但 beforeDestroy 里忘了 clearInterval。路由切走后组件销毁,定时器还在跑,回调里引用了组件实例和 DOM,导致整棵 DOM 树无法回收。

// 问题代码
mounted() {
  this.timer = setInterval(() => {
    this.fetchData(); // 引用 this,组件无法回收
  }, 5000);
}

// 修复
beforeDestroy() {
  clearInterval(this.timer);
  this.timer = null;
}

其他常见泄漏源

  • addEventListener 没 remove
  • 全局事件总线 on 了没 off
  • 未取消的 fetch / axios 请求,回调里 setState
  • 闭包引用了大对象
  • Vuex / Pinia 里存了组件实例
  • 第三方图表库(ECharts)实例没 dispose

预防

写组件时养成习惯:mounted 里注册了什么,beforeDestroy 里就反注册什么。ECharts 用 dispose(),WebSocket 用 close()。可以写一个 mixin 统一管理。

和喜欢的一切在一起~
最后更新于 2023-08-14