使用vue时遇到的内存溢出以及处理

7,317 阅读2分钟

业务场景

  • vue帮我们处理很多数据到视图、数据到事件的处理,其中不乏许多闭包、事件处理,因此比较容易忽视内存溢出的处理。

前言

几种常见的内存溢出
1. 全局变量引起的内存泄漏
2. 闭包引起的内存泄漏
3. dom清空或删除时,事件未清除导致的内存泄漏
4. 被遗忘的计时器或回调函数

全局变量引起的内存泄漏

在window下声明的变量不会被回收,因为window不会被回收.

{
    created(){
        if (!window.a) {
      window.myVue = this;
      this.bb = 123;
    }
    console.log(window.myVue, this, window.myVue === this);
    }
}

路由切换之后,此component不会被释放(但是router会重新生成一个此实例,原先的仍旧没有GC),window.myVue指向此对象

闭包引起的内存泄漏

//vue/src/core/vdom/modules/directives.js
    function _update(){
   // 用来更新vdom,创造,以及销毁vdom
    }
// vue/src/core/vdom/helpers/merge-hook.js
 function wrappedHook () {
    hook.apply(this, arguments)
// important: remove merged hook to ensure  its called only once and prevent memory leak
    remove(invoker.fns, wrappedHook)  //移除调用者的回调
  }
  // vue/src/core/vdom/helpers/update-listeners
  function createFnInvoker(){
  //接受一个函数或者一个Function[ ] ,
  返回一个调用者函数,并在此函数上保留传入的参数
  }

在vue中,这几个函数都有副作用(指除了修改自身的变量,还修改函数外的变量),因此如果传入的变量父对象,就算没有被引用,也无法被GC回收。 因此,这里进行了remove手动释放。

dom清空或删除时,事件未清除导致的内存泄漏

// 一个图片懒惰加载引擎示例
class ImageLazyLoader {
 constructor ($photoList) {
  $(window).on('scroll', () => {
   this.showImage($photoList);
  });
 }
 showImage ($photoList) {
  $photoList.each(img => {
   // 通过位置判断图片滑出来了就加载
   img.src = $(img).attr('data-src');
  });
 }
}
// 点击分页的时候就初始化一个图片懒惰加载的
$('.page').on('click', function () {
 new ImageLazyLoader($('img.photo'));
});

这是一个图片懒加载,photoList,有两处引用:dom引用和scroll事件。
当点击分页的时候,这个dom引用被移除,但是此时photoList仍旧被scroll事件引用,因此该数组并不会被GC。 正确的操作是 clear () {
$(window).off('scroll', this.scrollShow); } 在点击分页的时候,将此事件进行解绑

vue中,比如你写了一个dialog组件,但是你需要手动在created中监听某个按钮事件button
this.$dialog.$on("button", () => {
    console.log(this.xxx)
})

与this.xxx关联的有2者:该语句的上下文,dialog的分发on数组中,当此上下文切换的时候(上下文的dom引用移除),理应被GC的时候,由于此监听没有被移除,因此,并不会被GC。

被遗忘的计时器或回调函数

{
    created(){
    setInterval(()=> {
        console.log(this)
    },500)      
    }
}

调试方法

 打开f12进入Memory,选中heap snapshot(堆快照),没进行一次操作就

点一下这个原点,比较两次内存有没有回收

比如上上文的挂载在window全局的组件

找到引用的这个对象,手动GC就好啦

参考:一个Vue页面的内存泄露分析