1、內(nèi)存泄漏與內(nèi)存溢出
-
內(nèi)存泄漏(Memory Leak): 不再用到的內(nèi)存,沒有及時(shí)釋放;
-
內(nèi)存溢出(Out Of Memory): 應(yīng)用系統(tǒng)中存在無法回收的內(nèi)存或使用的內(nèi)存過多,最終使得程序運(yùn)行要用到的內(nèi)存大于能提供的最大內(nèi)存。
2、泄漏原因
-
js
寫法(閉包、全局變量等)、dom
事件監(jiān)聽、循環(huán)定時(shí)器等這些造成的泄漏; -
組件的泄漏(
DOM
泄漏即DOM
無法銷毀)導(dǎo)致DOM
上掛載的事件,對(duì)象數(shù)組等的數(shù)據(jù)也跟著無法釋放。
3、chrome Memory 介紹
打開控制臺(tái)上的Memory
面板或者按住F12
打開。
選擇堆快照類型。我一般是使用前兩種:Heap snapshot(JS堆快照)
和Allocation instrumentation on timeline(JS堆分配時(shí)間線)
。
開始錄制前先點(diǎn)擊下垃圾回收–>點(diǎn)擊開始錄制。如果JS
堆內(nèi)存動(dòng)態(tài)分配時(shí)間線,結(jié)束之前要再點(diǎn)擊下垃圾回收,再結(jié)束錄制。
4、解決辦法
4.1、JS堆快照
Summary
總覽視圖: 按構(gòu)造函數(shù)分組。用于捕捉對(duì)象及其使用的內(nèi)存。對(duì)于定位DOM內(nèi)存泄露特別有用。Comparison
對(duì)比視圖: 對(duì)比兩個(gè)快照。用于對(duì)比不同操作之后的堆快照,查看內(nèi)存的釋放及引用計(jì)數(shù),來分析內(nèi)存是否泄露及其原因。Containment
內(nèi)容視圖: 查看堆內(nèi)容。更適合查看對(duì)象結(jié)構(gòu),有助于分析對(duì)象的引用情況。適用于分析閉包以及深入分析對(duì)象。Statistics
統(tǒng)計(jì)視圖: 總覽堆的統(tǒng)計(jì)信息。
Summary
總覽視圖
說明:Constructor:
構(gòu)造函數(shù),節(jié)點(diǎn)下的對(duì)象都是由改構(gòu)造函數(shù)創(chuàng)建而來。Distance:
與根節(jié)點(diǎn)的距離。Objects Count:
對(duì)象個(gè)數(shù)及百分占比。Shallow size:
對(duì)象的直接內(nèi)存總數(shù),直接內(nèi)存是指對(duì)象自身占用的內(nèi)存大小。Retained size:
對(duì)象的最大保留內(nèi)存,保留內(nèi)存是指對(duì)象被刪除后可以釋放的那部分內(nèi)存。
點(diǎn)擊展開構(gòu)造函數(shù),可以看到所有構(gòu)造函數(shù)相關(guān)的對(duì)象實(shí)例,@后面的數(shù)字是該對(duì)象實(shí)例的唯一標(biāo)識(shí)符。
常見的頂層構(gòu)造函數(shù):
-
(global property):
全局對(duì)象和普通對(duì)象的中間對(duì)象,和常規(guī)思路不同。比如在Window上定義了一個(gè)Person對(duì)象,那么他們之間的關(guān)系就是[global] => (global property) => Person
。之所以使用中間對(duì)象,是出于性能的考慮。 -
(closure):
使用函數(shù)閉包的對(duì)象。 -
(array, string, number, regexp):
一系列對(duì)象類型,其屬性指向Array/String/Number/Regexp。
-
HTMLDivElement/HTMLAnchorElement/DocumentFragment:
元素的引用或者代碼引用的指定文檔對(duì)象。
記住,黃色的對(duì)象實(shí)例表示它被JS代碼引用,紅色的對(duì)象實(shí)例表示被黃色節(jié)點(diǎn)引用的游離節(jié)點(diǎn)。新版本(測(cè)試過69)的好像不會(huì)有顏色標(biāo)識(shí)。
JS堆快照可以用來發(fā)現(xiàn)DOM泄露。在Class filter(類過濾器)文本框中輸入Detached可以搜索分離的DOM樹。如果分離節(jié)點(diǎn)被JS引用,有可能就是泄露點(diǎn)。以下面這段代碼為例:
<html>
<head>
</head>
<body>
<button id="createBtn">增加節(jié)點(diǎn)</button>
<script>
function create() {
var ul = document.createElement('ul');
for (var i = 0; i < 10; i++) {
var li = document.createElement('li');
ul.appendChild(li);
}
detachedNodes = ul;
}
document.getElementById('createBtn').addEventListener('click', create);
</script>
</body>
</html>
點(diǎn)擊快照之前要點(diǎn)擊垃圾回收
點(diǎn)擊一次“增加節(jié)點(diǎn)”按鈕后,錄制快照如下:
發(fā)現(xiàn) 有個(gè)< ul >分離節(jié)點(diǎn),被window.detachedNodes
引用。看下代碼原來是沒有加var聲明,導(dǎo)致其成了全局變量。所以DOM無法釋放。
Comparasion
對(duì)比視圖
為了驗(yàn)證特定操作會(huì)不會(huì)引起內(nèi)存泄露,對(duì)比快照的步驟如下:
1、無任何操作,拍第一個(gè)堆快照
2、執(zhí)行你覺得可能造成內(nèi)存泄露的操作,再執(zhí)行相反操作
3、拍第二個(gè)堆快照,切換到對(duì)照視圖,并且指定與第一個(gè)堆快照對(duì)比
比如你覺得登陸頁面內(nèi)存泄露,那可以先登陸到首頁,拍第一個(gè)堆快照。然后退出到登陸界面,再重新登陸到首頁,錄制第二個(gè)快照。比對(duì)這兩個(gè)快照的大小,如果增長有可能是泄露,可以反復(fù)操作幾次。記得每次錄制之前要先點(diǎn)擊垃圾回收。
使用對(duì)比可以看到第一次和第二次快照不同地方
注意:Chrome
開發(fā)者工具中Memory
功能排查,你會(huì)發(fā)現(xiàn)怎么每個(gè)組件都存在內(nèi)存泄漏,導(dǎo)致無從下手
這時(shí)候我們就要采用排除法來找出泄露點(diǎn),之前說過是切換主菜單時(shí)發(fā)生內(nèi)存泄漏,那首先把每個(gè)菜單頁面內(nèi)容全注釋,再切換主菜單,經(jīng)測(cè)試沒有內(nèi)存泄漏。
查看快照Containment view
內(nèi)容視圖
內(nèi)容視圖其實(shí)就是應(yīng)用對(duì)象結(jié)構(gòu)的鳥瞰圖。它能讓你深入分析函數(shù)閉包,觀察VM內(nèi)部對(duì)象,查看應(yīng)用底層的內(nèi)存使用情況。
該視圖提供了幾個(gè)常見入口:
-
DOMWindow objects
:JavaScript
代碼的全局對(duì)象 -
Native objects:
瀏覽器的原生對(duì)象,整合到JS虛擬機(jī)中便于操作,比如DOM
節(jié)點(diǎn),CSS
規(guī)則。
關(guān)于閉包的一個(gè)小建議:命名函數(shù)的閉包相對(duì)匿名函數(shù)的閉包更易于分析調(diào)試。
// 匿名閉包
function createLargeClosure() {
var largeStr = new Array(1000000).join('x');
var lC = function() {
return largeStr;
};
return lC;
}
// 命名閉包
function createLargeClosure() {
var largeStr = new Array(1000000).join('x');
var lC = function lC() {
return largeStr;
};
return lC;
}
查看快照Statistics 統(tǒng)計(jì)視圖
總覽堆棧的統(tǒng)計(jì)信息??梢郧宄目闯龆芽煺盏姆植记闆r。
4.2、JS堆分配時(shí)間線
通過Allocation instrumentation on timeline
可以持續(xù)的記錄堆分配的情況,顯示了對(duì)象在什么時(shí)候被創(chuàng)建、什么時(shí)候存在內(nèi)存泄漏等。
上面的柱條表示堆中生成的新對(duì)象。高度表示這個(gè)對(duì)象的大小,顏色表示這個(gè)對(duì)象的內(nèi)存釋放情況:藍(lán)色柱表示這個(gè)對(duì)象在timeline
中生成,結(jié)束前仍然存在;灰色柱表示這個(gè)對(duì)象在timeline
中生成,但結(jié)束前已經(jīng)被回收了。
我們可以重復(fù)執(zhí)行某個(gè)動(dòng)作如果最后有不少藍(lán)色柱被保留,這些藍(lán)色柱就是潛在的內(nèi)存泄露問題。
如果左邊的意料之外的藍(lán)條,那么極有可能存在內(nèi)存泄露。文章來源:http://www.zghlxwxcb.cn/news/detail-507926.html
上面是Vue
項(xiàng)目反復(fù)切換兩個(gè)錄制的堆分配行為,我們可以聚焦到某一次堆分配,查看具體對(duì)象信息??梢栽谥鶢顖D中滑動(dòng)鼠標(biāo)滾輪查看某段時(shí)間的堆分配。比如上面發(fā)現(xiàn)有三個(gè)VueComponent
沒有回收。點(diǎn)擊展開查看詳細(xì)信息。發(fā)現(xiàn)這三個(gè)組件的信息都是一樣的,那就是組件沒有釋放。首先確認(rèn)組件是否被銷毀。如果已銷毀,確認(rèn)事件是否解綁、定時(shí)器是否取消,特別注意事件總線綁定的事件一定要解綁。
要注意VueComponent
的泄漏值,因?yàn)?code>VueComponent是會(huì)掛載對(duì)象、數(shù)據(jù)、事件的,所以那些Object Array
產(chǎn)生泄漏值也很大可能是VueComponent
造成的。所以我們?cè)谔幚硇孤┑臅r(shí)候最好是先保證VueComponent
的泄漏值為0. 然后再去往js閉包、循環(huán)定時(shí)器、事件監(jiān)聽那些方向去檢查。文章來源地址http://www.zghlxwxcb.cn/news/detail-507926.html
到了這里,關(guān)于如何看內(nèi)存占用情況,vue反復(fù)刷新標(biāo)簽頁導(dǎo)致面內(nèi)存一直在漲,系統(tǒng)反應(yīng)越來越慢,內(nèi)存占用4個(gè)g。的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!