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