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中禁止使用。可以考慮使用防抖隊列。