Catching memory leaks with Chrome DevTools 當(dāng)分配的內(nèi)存沒有返回給操作系統(tǒng)或內(nèi)存池時(shí),,我們將其稱為內(nèi)存泄漏。 在這種情況下,內(nèi)存未被任何應(yīng)用程序使用,并且被不必要地占用,。 這會(huì)導(dǎo)致低性能、高延遲和頻繁崩潰,。 Understanding memory leaks如果您熟悉 C 等低級(jí)語言,,您一定使用過 malloc() 和 free()。 相比之下,,JavaScript 在創(chuàng)建對(duì)象時(shí)自動(dòng)分配內(nèi)存,,并在不再使用時(shí)釋放它。 好吧,,因?yàn)樗亲詣?dòng)管理的,,所以我們作為開發(fā)人員總是有一個(gè)錯(cuò)誤的印象,即我們不需要擔(dān)心瀏覽器中的內(nèi)存管理,。 如果一個(gè)站點(diǎn)使用越來越多的內(nèi)存,,這意味著沒有人收集它并且存在內(nèi)存泄漏。 Garbage collectors如果垃圾收集器 (GC) 是完美的,,那么內(nèi)存泄漏就不是問題,。 問題是他們的算法不夠聰明,無法檢測(cè)內(nèi)存泄漏,。 因此,,需要人工干預(yù)。 垃圾收集器執(zhí)行查找程序不再使用的內(nèi)存并將其釋放回操作系統(tǒng)以供將來重新分配的過程,。 該方法有效,,但仍然會(huì)發(fā)生內(nèi)存泄漏,。 該方法無法檢測(cè)每個(gè)泄漏,例如泄漏的引用,。 Why is there a memory leak?下列是幾種常見的內(nèi)存泄漏類型,。 Accidental global variablesfunction getWork() { this.work = “I am Memory leak”; } // The this here refers to window object and hence this variable will be created in the window. getWork(); 這里的 this 指的是 window 對(duì)象,因此這個(gè)變量將在 window 中創(chuàng)建,。 由于全局變量不是由 GC 收集的,,如果此字符串變得太大,可能會(huì)導(dǎo)致內(nèi)存泄漏,。 意外全局變量的一個(gè)類似示例是在不使用 let 和 var 關(guān)鍵字的情況下聲明變量,。 Detached DOM nodes分離 DOM 節(jié)點(diǎn)是一個(gè)關(guān)鍵問題。 由于全局引用,,分離的節(jié)點(diǎn)仍然存在于內(nèi)存中,。 var node = document.createElement('a’); node.id = 'id1'; document.body.appendChild(node); var main = { Id: document.getElementById('id1’) } function removeElement(){ document.body.removeChild(document.getElementById('id1’)); } removeElement(); 在上面的例子中,removeChild 函數(shù)從樹中移除了 DOM 節(jié)點(diǎn),,但是全局主對(duì)象中的引用 Id 仍然保留在內(nèi)存中并且沒有被垃圾收集,。 閉包閉包為內(nèi)部函數(shù)維護(hù)外部函數(shù)變量的范圍,即使在外部函數(shù)的范圍之外,。 function getScore(x) { function score(y) { return x + y; } return score; } var initial = getScore(2); var final = initial(3); 這里的函數(shù)score,也就是內(nèi)部函數(shù),,有一個(gè)全局引用,,叫做initial。 這個(gè)初始引用永遠(yuǎn)不會(huì)被垃圾收集,。 Tools to identify memory leaks意外的全局變量 內(nèi)存泄漏可以通過分析輕松檢測(cè)到,。 我們舉一個(gè)代碼片段的例子,它會(huì)因?yàn)槿肿兞慷鴮?dǎo)致內(nèi)存泄漏,。 例子: var x = [] var bool = false; function grow(){ x.push(new Array(100000).join('a’)); if(bool){ setTimeout(grow, 1000); } } function start(){ grow(); bool = true; } function stop(){ bool = false; } 到 Chrome 開發(fā)者工具里,,打開 Profiles 標(biāo)簽頁: 選擇 Take Heap Snapshot. 在這里,window 對(duì)象的黃色實(shí)際上描繪了從 JS 代碼中直接引用的節(jié)點(diǎn),。 我們需要修復(fù)這里的代碼,,以便我們可以擺脫黃色標(biāo)記。 此處的選項(xiàng)是在函數(shù)內(nèi)將數(shù)組設(shè)為局部,,以便垃圾收集器可以收集它或顯式刪除全局變量,。 您可以找到更正后的代碼: var bool = false; function grow(){ var x = []; x.push(new Array(100000).join('a’)); if(bool){ setTimeout(grow, 1000); } } function start(){ grow(); bool = true; } function stop(){ bool = false; } Allocation profilerAllocation Timeline 是另一個(gè)工具,可以幫助您跟蹤 JS 堆中的內(nèi)存泄漏,。 要記錄時(shí)間線,,請(qǐng)轉(zhuǎn)到您的 profile 面板,然后單擊上面給出的相同代碼的開始,。 當(dāng)我們單擊如圖所示的開始按鈕并使用分配分析器進(jìn)行配置時(shí),,我們可以看到它生成了如圖所示的藍(lán)線。 藍(lán)條代表新的內(nèi)存分配,這可能是內(nèi)存泄漏,。 您可以通過縮放這些藍(lán)色條中的任何一個(gè)來查看詳細(xì)信息,。 此處的詳細(xì)信息表示被推入數(shù)組且從不進(jìn)行垃圾回收的長(zhǎng)字符串。 |
|