1、学会使用devTool
参考文章
Memory详解:
a、需要使用Memory来分析内存变化,至少记录两次内存快照,用于做内存变化比对。
举例:
编辑器有内存溢出,所以在打开前记录一次快照,打开编辑器等待加载完成,然后关闭编辑器,再记录一次快照。
两次快照间的内存差异,很大可能是内存溢出部分。当然,也有可能是一些依赖增长,此时多次打开关闭,观察内存变化,持续累积的部分必然是内存溢出。
b、关注detachDomElement
detach的元素表示这些DOM元素不在DOM树中,但是有被js对象所引用。
一般来说,这是内存溢出查找的主要入口。
查找的流程
1、找到shallow size较大的元素,一般来说会是HTMLDivElement,任意选中其中的一项,可以看到以下内容:
该清单表示它的被引用情况,此时,重点关注以下几项:
1、用户写的对象
2、监听
3、context上下文,上下文表示一些未被回收的函数中,有使用到相关对象
2、常见的解决方案
1 监听的问题
很多开发者在使用观察者模式后,忘了写对应的注销代码,这是大忌。不论是js、jquery、vue还是自己写的监听,都必须有对应的注销代码。
有on就得有off。
有addListener就得有removeListener。
举例:
在mounted的时候注册的监听,在beforeDestroy时候销毁。
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中禁止使用。可以考虑使用防抖队列。