摘要:導(dǎo)致內(nèi)存泄漏的原因沒有完全切斷與之間的路徑因?yàn)闆]有完全切斷與根節(jié)點(diǎn)之間的路徑,導(dǎo)致自動(dòng)不會(huì)回收這部分內(nèi)存,從而造成內(nèi)存泄漏。在下一篇文章中,將闡述如何確定內(nèi)存泄漏,以及可以使用的工具和方法。
JS有完善的內(nèi)存處理機(jī)制,所以之前我們不用特別的去關(guān)注這塊的實(shí)現(xiàn)。頁面不快了,刷新一下就好了;瀏覽器卡頓,重啟一下就OK。但是隨著SPA和移動(dòng)APP的流行,以及未來可能存在的PWA的實(shí)現(xiàn),JS內(nèi)存可能成為新的內(nèi)存瓶頸。這也是寫本文的初衷。1.什么是內(nèi)存泄漏
當(dāng)我們決定不再使用某些內(nèi)存時(shí),由于錯(cuò)誤的編碼,未能使得GC(Gabbage Collection)正確的將這些內(nèi)存回收的情況,就是內(nèi)存泄漏。
2.內(nèi)存的占用,分配和回收 2.1 內(nèi)存的占用
一個(gè)對(duì)象占用的內(nèi)存分為直接占用內(nèi)存(Shallow Size)和占用總內(nèi)存(Retained Size)。
直接占用內(nèi)存:對(duì)象本身占用的內(nèi)存。典型的JavaScript對(duì)象都會(huì)有保留內(nèi)存用來描述這個(gè)對(duì)象和存儲(chǔ)它的直接值。一般,只有數(shù)組和字符串會(huì)有明顯的直接占用內(nèi)存(Shallow Size)。但字符串和數(shù)組常常會(huì)在渲染器內(nèi)存中存儲(chǔ)主要數(shù)據(jù)部分,僅僅在JavaScript對(duì)象棧中暴露一個(gè)很小的包裝對(duì)象。
占用總內(nèi)存:直接占用內(nèi)存和這個(gè)引用的依賴對(duì)象所占用的內(nèi)存。
賦值和New操作都會(huì)涉及到內(nèi)存的占用。
2.2 內(nèi)存的分配Chrome V8的垃圾回收(GC)算法基于Generational Collection,內(nèi)存被劃分為兩種,分別稱為Young Generation(YG)和Old Generation(OG)。
所謂Young和Old是根據(jù)他們占用的時(shí)間來劃分的。內(nèi)存在YG的分配和回收快而頻繁,一般存在的時(shí)間很短,所以稱為Young;而在OG中則慢而少發(fā)生,所以稱為Old。
因?yàn)樵赩8中,YG的GC過程會(huì)阻塞程序,而OG的GC不會(huì)阻塞。所以通常情況下開發(fā)者更關(guān)心YG的細(xì)節(jié)。
YG又被平分為兩部分空間,分別稱為From和To。所有內(nèi)存從To空間被分配出去,當(dāng)To滿時(shí),開始觸發(fā)GC,接下來細(xì)看一下。
某時(shí)刻,To已經(jīng)分A、B和C分配了內(nèi)存,當(dāng)前它剩下一小塊內(nèi)存未分配出去,而From所有的內(nèi)存都空閑著。
此時(shí),一個(gè)程序需要為D分配內(nèi)存,但D需要的內(nèi)存大小超出了To未分配的內(nèi)存,如下圖。此時(shí),觸發(fā)GC,頁面停止執(zhí)行。
接著From和To進(jìn)行對(duì)換,即原來的To空間被標(biāo)志為From,F(xiàn)rom被標(biāo)志為To。并且把活的變量值(例如B)標(biāo)志出來,而”垃圾“(例如AC)未被標(biāo)志,它們將會(huì)被清掉。
活的B會(huì)被復(fù)制到To空間,而「垃圾」AC則被回收,同時(shí),D被分配到To空間,最后成下圖的分布
至此,整個(gè)GC完成,此過程中頁面停止執(zhí)行,所以要盡可能的快。當(dāng)YG中的值存活比較久時(shí),它會(huì)被推向OG,OG的空間滿時(shí),觸發(fā)OG內(nèi)的GC,OG的GC時(shí)會(huì)觸發(fā)YG的GC。
每次分配都使To的可用空間減小,程序又更接近GC
YG的GC會(huì)阻塞程序,所以GC時(shí)間不宜太長10ms以內(nèi),因?yàn)?6ms就會(huì)出現(xiàn)丟幀;GC不宜太頻繁
某個(gè)值變成垃圾后,不會(huì)立馬釋放內(nèi)存,只有在GC的時(shí)候所占內(nèi)存才會(huì)被回收。
2.2 內(nèi)容均來自參考文獻(xiàn)
2.3 內(nèi)存的回收GC Root是內(nèi)存的根結(jié)節(jié),在瀏覽器中它是window,在NodeJS中則是global對(duì)象。
從GC Root開始遍歷圖,所有能到達(dá)的節(jié)點(diǎn)稱為活節(jié)點(diǎn),如果存在GC Root不能到達(dá)的節(jié)點(diǎn),那么該節(jié)點(diǎn)稱為“垃圾”,將會(huì)被回收,如圖中灰色的節(jié)點(diǎn)。
至于根節(jié)點(diǎn)的回收,不受用戶的控制。
3. 導(dǎo)致內(nèi)存泄漏的原因 3.1 沒有完全切斷與GC root之間的路徑因?yàn)闆]有完全切斷與根節(jié)點(diǎn)之間的路徑,導(dǎo)致自動(dòng)GC不會(huì)回收這部分內(nèi)存,從而造成內(nèi)存泄漏。
具體的原因有:
對(duì)象之間的相互引用
var a, b; a.reference = b; b.reference = a;
錯(cuò)誤使用了全局變量
a = "1234567"; 相當(dāng)于 window.a = "1234567";
DOM元素清空或刪除時(shí),綁定的事件未清除
閉包引用
function bindEvent() { var obj = document.getElementById("xxx"); obj.onclick = function () { /** 空函數(shù)*/ }; /** delete this reference */ // obj = null; }
DOM元素清空或刪除時(shí),子元素存在JS引用,導(dǎo)致子元素的所有父元素都不會(huì)被刪除
// b是a的子dom節(jié)點(diǎn), a是body的子節(jié)點(diǎn) var aElement = document.getElementById("a"); var bElement = document.getElementById("b"); document.body.removeChild(aElement); // aElement = null; // bElement = null;3.2 過度占用了內(nèi)存空間
更多的出現(xiàn)在nodejs中,例如:
無節(jié)制的循環(huán)
while(1) { // do sth }
過大的數(shù)組
var arr = []; for (var i=0; i< 100000000000; i++) { var a = { "desc": "an object" } arr.push(a); }總結(jié)
本文描述了內(nèi)存分配和泄漏的基本原理,并提及了日常常遇到的集中的泄漏原因。在下一篇文章中,將闡述如何確定內(nèi)存泄漏,以及可以使用的工具和方法。
參考文獻(xiàn):《Chrome開發(fā)者工具之JavaScript內(nèi)存分析》
《【精耕細(xì)作】授你兇器,一見JS內(nèi)存》from kenshinlin
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/107510.html
摘要:自動(dòng)內(nèi)存管理當(dāng)你在使用時(shí),實(shí)際上并不需要考慮內(nèi)存。這種自動(dòng)內(nèi)存管理可以使開發(fā)人員更輕松。即使在手動(dòng)內(nèi)存管理的語言中,通常會(huì)從語言運(yùn)行時(shí)獲得一些幫助。這就是為什么許多現(xiàn)代語言使用自動(dòng)內(nèi)存管理的原因避免人為錯(cuò)誤。 原文地址:A crash course in memory management 原文作者:Lin Clark 譯者:黑黑 校對(duì)者:Bob 要理解為什么將 Array...
摘要:你可以從內(nèi)存中直接拿東西,也可以直接往內(nèi)存里存東西當(dāng)你把或者其它語言編譯為時(shí),編譯工具會(huì)在里增加一些輔助代碼。 作者:Lin Clark 譯者:Cody Chan 原帖鏈接:A crash course in memory management 這是圖解 SharedArrayBuffers 系列的第一篇: 內(nèi)存管理碰撞課程 圖解 ArrayBuffers 和 SharedA...
摘要:內(nèi)存泄露內(nèi)存泄露概念在計(jì)算機(jī)科學(xué)中,內(nèi)存泄漏指由于疏忽或錯(cuò)誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存。判斷內(nèi)存泄漏,以字段為準(zhǔn)。 本文是 重溫基礎(chǔ) 系列文章的第二十二篇。 今日感受:優(yōu)化學(xué)習(xí)方法。 系列目錄: 【復(fù)習(xí)資料】ES6/ES7/ES8/ES9資料整理(個(gè)人整理) 【重溫基礎(chǔ)】1-14篇 【重溫基礎(chǔ)】15.JS對(duì)象介紹 【重溫基礎(chǔ)】16.JSON對(duì)象介紹 【重溫基礎(chǔ)】1...
摘要:正好最近在學(xué)習(xí)的各種實(shí)現(xiàn)原理,在這里斗膽翻譯一篇垃圾回收機(jī)制原文鏈接。自動(dòng)管理的機(jī)制中,通常都會(huì)包含垃圾回收機(jī)制。二垃圾回收機(jī)制的概念垃圾回收,是一種自動(dòng)管理應(yīng)用程序所占內(nèi)存的機(jī)制,簡稱方便起見,本文均采用此簡寫。 最近關(guān)注了一個(gè)國外技術(shù)博客RisingStack里面有很多高質(zhì)量,且對(duì)新手也很friendly的文章。正好最近在學(xué)習(xí)Node.js的各種實(shí)現(xiàn)原理,在這里斗膽翻譯一篇Node...
摘要:使用,您可以直接訪問原始字節(jié)碼這可能令人擔(dān)憂。可以根據(jù)索引從中拿到字符串現(xiàn)在,很多人并不知道如何在中使用字節(jié)碼。你需要將字節(jié)碼轉(zhuǎn)換為有用的內(nèi)容,比如說字符串。通過防止瀏覽器級(jí)內(nèi)存泄漏并提供內(nèi)存隔離,使事情變得更安全。 原文鏈接:https://fanmingfei.com/posts/... 這是系列文章第二篇: 使用 JavaScript 創(chuàng)建一個(gè) WebAssembly 模塊的實(shí)...
閱讀 2947·2023-04-25 19:20
閱讀 794·2021-11-24 09:38
閱讀 2052·2021-09-26 09:55
閱讀 2439·2021-09-02 15:11
閱讀 2053·2019-08-30 15:55
閱讀 3615·2019-08-30 15:54
閱讀 3154·2019-08-30 14:03
閱讀 2967·2019-08-29 17:11