前端内存泄漏排查手册

237 阅读3分钟

1. 内存泄漏是什么

内存泄漏是变量不再被使用本来应该被释放了,但是因为不合理的引用导致没有被释放,占用了一定的内存,甚至导致内存暴涨,进而程序崩溃。

2. 如何排查内存泄漏

查看浏览器的标签页

鼠标经过浏览器的标签页会出现内存用量的提示,如果浏览器出现了内存泄漏,能在这里很直接的看出来,在某个时间点之后内存涨了

image.png

浏览器的任务管理器

这里能够看到某个操作进行的同时,内存发生的变化,进而侦测内存泄漏,如果切换到某个页面或者某个操作之后,内存增加了非常多,则可能是出现了内存泄漏 image.png

image.png

浏览器的Memory工具

通过多次操作+打快照的对比,能够看出是否发行内存泄漏。右侧能够看到代码内存占用的情况 tutieshi_640x326_12s.gif

注意,垃圾回收机制我们无法代码直接控制,但是打快照时,我们可以直接点击按钮触发垃圾回收,再打快照或者看任务管理器,看看是否会下降

image.png

3. 内存泄漏排查

3.1 代码定位

  • 首先,最好能明确这真的是内存泄漏,还是只是正常现象。比如从A页面切换到B页面,内存是40MB,再切换到A,再切回B,此时变成了50甚至是80、100MB,这可以视为一种内存泄漏,可能是页面销毁时东西没有清理干净
  • 其次,可以通过return代码,定位到具体的代码

3.2 对象体积

数组或者对象的体积会影响到内存,尤其是后端返回10000+以上的数据, 此时多一个属性可能会多很多内存,把不需要的剔除出去

data[i].children.push({
    id: `${i}-${j}`,
    path: `/${i}-${i}`,
    name: `test-${i}-${j}`,
    children: [],
    showChildren: false,
    height: 180,
-    weight: 60,
-    gender: 'boy',
-    hobby: 'gaming'
});

3.3 闭包

闭包会导致内存泄漏,尤其是这个变量还很大的时候,如下arr本来是局部变量,但是在全局访问到了,他则不会被删除掉,不需要时记得清空他

function closure () {
  let arr = new Array(200000).fill(null).map(e => new MyObject())
  return function () {
    let arr2 = arr
  }
}
let arr = closure()
arr = null // 执行,才能清空变量

3.4 用到的定时器,事件监听,echarts图表在切换页面后记得清空一下

onUnmounted(() => {
    clearInterval(timer.value);
    window.removeListener('click', fn)
    myChart.value.dispose()
})

3.5 删除不必要的console.log

如果console.log打印了很大的变量,可能也会导致内存泄漏

3.5 axios使用cancelToken

如果从点击进入A页面,立马切换到B页面,此时A页面的接口可能已经发出去拿数据了,这也会占用内存。我们可以把cancelToken存储在store里面去

const { isCancel } = axios
service.interceptors.request.use(
  config => {
    let CancelToken = axios.CancelToken;
    let source = CancelToken.source();
    //  getters里面没有token,
    if(!store.getters.initCancelTokenSource){
      store.dispatch("modCancelToken",source)
      config.cancelToken = source.token
    }else {
    // getters里面有token
      config.cancelToken = store.getters.initCancelTokenSource.token
    }