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