JS、VUE内存溢出问题的解决方案

1、学会使用devTool

参考文章

 

Memory详解:

a、需要使用Memory来分析内存变化,至少记录两次内存快照,用于做内存变化比对。

image.png

 

举例:

编辑器有内存溢出,所以在打开前记录一次快照,打开编辑器等待加载完成,然后关闭编辑器,再记录一次快照。

两次快照间的内存差异,很大可能是内存溢出部分。当然,也有可能是一些依赖增长,此时多次打开关闭,观察内存变化,持续累积的部分必然是内存溢出。

 

b、关注detachDomElement

 

detach的元素表示这些DOM元素不在DOM树中,但是有被js对象所引用。

一般来说,这是内存溢出查找的主要入口。

image.png

 

查找的流程

1、找到shallow size较大的元素,一般来说会是HTMLDivElement,任意选中其中的一项,可以看到以下内容:

image.png

 

该清单表示它的被引用情况,此时,重点关注以下几项:

1、用户写的对象

2、监听

3、context上下文,上下文表示一些未被回收的函数中,有使用到相关对象

 

 

2、常见的解决方案

 

1 监听的问题

很多开发者在使用观察者模式后,忘了写对应的注销代码,这是大忌。不论是js、jquery、vue还是自己写的监听,都必须有对应的注销代码。

 

有on就得有off。

有addListener就得有removeListener。

 

举例:

在mounted的时候注册的监听,在beforeDestroy时候销毁。

image.png

 

2、VUE本身的问题

 

VUE挂载了大量的对象,有可能因为用户代码的介入,导致无法销毁,所以加入以下代码:

 

const cleanVnode=vnode=>{
  if(vnode){
    vnode.elm = null;
    vnode._renderChildren=null;
    vnode.children=null;
    // vnode.context=null;
    vnode.componentOptions=null;
  }
}

Vue.mixin({
  beforeDestroy() {
    if(this.$el)
    delete this.$el.__vue__;
  },
  destroyed() {
    //为了内存,清空所有内容
    this.$children = [];
    this.$parent = null;
    this._watchers = [];
    this.$refs = {};
    this.$root = null;
    this.$slots = [];
    this.$store = null; 
    cleanVnode(this._vnode);
    cleanVnode(this.$vnode)
    this._vnode = null;
    this.$vnode = null;
    if(this.$el)
    delete this.$el.__ro__;
    this.$el = null;
    // this.$el=null;
    this._watcher = null;
    this._computedWatchers = {};
    //ab-aui的内存溢出问题
    this.popperElm=null;
    if(this.$options){
      this.$options.parent=null;
      this._parentVnode=null;
      this.$options=null;
    }
  },
})

 

需要注意,该代码由于this.$el的销毁,可能会造成一些bug。

 

 

3、全局对象的问题

 

a、减少全局对象的时候,关闭对象的时候,也要其销毁在全局对象中的对应引用。

b、vue+全局对象可能有的观察者(监听)问题,vue会在对象中注册__ob__,ob指的是observe,所以需要销毁这些内容。推荐delete 全局对象.__ob__。

 

4、monacoEditor的问题

monacoEditor也有内存溢出问题,虽然它提供了dispose函数,但是我发现有时它销毁不了所有对象。

自行销毁方式如下:

//this.editor为MonacoEditor实例
    this.editor && this.editor.dispose();
    let config = this.editor._contentWidgets[
      "editor.widget.suggestWidget"
    ];
    let x;
    if ((x = config && config.widget)) {
      x.dispose();
      x.elememt = null;
      x.editor = null;
      x.list.dispose();
      x.details.editor=null;
      x.details.dispose();
      for (let k in x) {
        delete x[k];
      }
    }
    for (let k in this.editor) {
      delete this.editor[k];
    }

    this.editor = null;
    this.__resize_ob = null;

 

5、VUE的computed中使用Vue.set的问题

Vue.set会触发观察,computed中禁止使用。可以考虑使用防抖队列。

posted @ 2020-06-19 16:09  荒土  阅读(5334)  评论(1编辑  收藏  举报