摘要:引用計數另一種不太常見的垃圾回收策略是引用計數。引用計數的含義是跟蹤記錄每個值被引用的次數。在采用引用計數的策略中,由于函數執行之后,這兩個對象都離開了作用域,函數執行完成之后,和還將會繼續存在,因為他們的引用次數永遠不會是。
垃圾回收的必要性
由于字符串、對象和數組沒有固定大小,所以當他們的大小已知時,才能對他們進行動態的存儲分配。JavaScript程序每次創建字符串、數組或對象時,解釋器都必須分配內存來存儲那個實體。只要像這樣動態地分配了內存,最終都要釋放這些內存以便他們能夠被再用,否則,JavaScript的解釋器將會消耗完系統中所有可用的內存,造成系統崩潰。 ---《JavaScript權威指南(第四版)》
JavaScript的解釋器可以檢測到何時程序不再使用一個對象了,當他確定了一個對象是無用的時候,他就知道不再需要這個對象,可以把它所占用的內存釋放掉了。例如:
var a = "before"; var b = "override a"; var a = b; //重寫a
這段代碼運行之后,“before”這個字符串失去了引用(之前是被a引用),系統檢測到這個事實之后,就會釋放該字符串的存儲空間以便這些空間可以被再利用。
垃圾回收原理最常采用的垃圾回收有兩種方法:標記清除、引用計數
標記清除當執行流入到一個函數中時,會創建該函數的執行環境,執行環境中的變量都會被標記為“進入環境”,從邏輯上講,永遠不能釋放“進入執行環境”變量所占用的內存。因為只要執行流入相應的執行環境,就可能會用到這些變量。
垃圾收集器在運行的時候會給存儲在內存的中的變量都加上標記。然后,它會去掉環境中的變量以及被環境中的變量引用的變量的標記。而在此之后再被加上標記的變量將被視為準備刪除的變量。最后,垃圾收集器完成內存清除工作,銷毀那些帶標記的值并回收它們所占用的內存空間。
另一種不太常見的垃圾回收策略是引用計數。引用計數的含義是跟蹤記錄每個值被引用的次數。當聲明了一個變量并將一個引用類型賦值給該變量時,則這個值的引用次數就是1。相反,如果包含對這個值引用的變量又取得了另外一個值,則這個值的引用次數就減1。當這個引用次數變成0時,則說明沒有辦法再訪問這個值了,因而就可以將其所占的內存空間給收回來。這樣,垃圾收集器下次再運行時,它就會釋放那些引用次數為0的值所占的內存。
但是用這種方法存在問題:
function problem(){ var objA = new Object() var objB = new Object() objA.someOtherObject = objB objB.someOtherObject = objA }
在這個例子中,objA和objB通過各自的屬性相互引用;也就是說這兩個對象的引用次數都是2。在采用引用計數的策略中,由于函數執行之后,這兩個對象都離開了作用域,函數執行完成之后,objA和objB還將會繼續存在,因為他們的引用次數永遠不會是0。這樣的相互引用如果說很大量的存在就會導致大量的內存泄露。
引起內存泄漏的操作 用全局變量緩存數據將全局變量作為緩存數據的一種方式,將之后要用到的數據都掛載到全局變量上,用完之后也不手動釋放內存(因為全局變量引用的對象,垃圾回收機制不會自動回收),全局變量逐漸就積累了一些不用的對象,導致內存泄漏
var x = []; function grow() { x.push(new Array(1000000).join("x")); /* 使用x數組進行某些操作 */ setTimeout(grow, 1000); } grow()沒有清理的DOM元素引用
(function () { var nodes = ""; var item = { // 為了凸顯 name: new Array(1000000).join("x") } nodes = document.getElementById("nodes") nodes.item = item nodes.parentElement.removeChild(nodes) })()
notes變量指向的是頁面中的一個元素(也是內存中的一塊空間),當將 notes 對應的元素從頁面中移除后,其在內存中對應的空間由于仍然由notes變量指向(引用),因此垃圾回收機制不會將這塊內存空間回收,從而導致內存泄漏
被遺忘的定時器或者回調var someResource = getData(); setInterval(function() { var node = document.getElementById("Node"); if(node) { node.innerHTML = JSON.stringify(someResource)); } }, 1000);
這樣的代碼很常見, 如果id為Node的元素從DOM中移除, 該定時器仍會存在, 同時, 因為回調函數中包含對someResource的引用, 定時器外面的someResource也不會被釋放.
閉包循環引用var theThing = null var replaceThing = function () { var originalThing = theThing var unused = function () { if (originalThing) console.log("hi") } theThing = { longStr: new Array(1000000).join("*"), someMethod: function () { console.log(someMessage) } }; }; setInterval(replaceThing, 1000)
這種內存泄漏的分析請參考here
參考《JavaScript權威指南》
javascript典型內存泄漏及chrome的排查方法
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83322.html
摘要:解決方式是,當我們不使用它們的時候,手動切斷鏈接淘汰把和對象轉為了真正的對象,避免了使用這種垃圾收集策略,消除了以下常見的內存泄漏的主要原因。以上參考資料高程垃圾收集類內存泄漏及如何避免內存泄露及解決方案詳解類內存泄漏及如何避免 showImg(http://ww1.sinaimg.cn/large/005Y4rCogy1ft1ikzcqzqj30ka0et77a.jpg); 前言 起...
摘要:所謂的內存泄漏簡單來說是不再用到的內存,沒有及時釋放。如果一個值不再需要了,引用數卻不為,垃圾回收機制無法釋放這塊內存,從而導致內存泄漏。 前言 程序的運行需要內存。只要程序提出要求,操作系統或者運行時就必須供給內存。所謂的內存泄漏簡單來說是不再用到的內存,沒有及時釋放。為了更好避免內存泄漏,我們先介紹Javascript垃圾回收機制。 在C與C++等語言中,開發人員可以直接控制內存的...
摘要:所謂的內存泄漏簡單來說是不再用到的內存,沒有及時釋放。如果一個值不再需要了,引用數卻不為,垃圾回收機制無法釋放這塊內存,從而導致內存泄漏。 前言 程序的運行需要內存。只要程序提出要求,操作系統或者運行時就必須供給內存。所謂的內存泄漏簡單來說是不再用到的內存,沒有及時釋放。為了更好避免內存泄漏,我們先介紹Javascript垃圾回收機制。 在C與C++等語言中,開發人員可以直接控制內存的...
摘要:介紹瀏覽器的具有自動垃圾回收機制,也就是說,執行環境會負責管理代碼執行過程中使用的內存。中的內存泄漏問題程序的內存溢出后,會使某一段函數體永遠失效取決于當時的代碼運行到哪一個函數,通常表現為程序突然卡死或程序出現異常。 showImg(https://segmentfault.com/img/remote/1460000018932880?w=4400&h=3080); 1. 介紹 瀏...
摘要:垃圾回收內存管理實踐先通過一個來看看在中進行垃圾回收的過程是怎樣的內存泄漏識別在環境里提供了方法用來查看當前進程內存使用情況,單位為字節中保存的進程占用的內存部分,包括代碼本身棧堆。 showImg(https://segmentfault.com/img/remote/1460000019894672?w=640&h=426);作者 | 五月君Node.js 技術棧 | https:...
閱讀 540·2021-08-31 09:45
閱讀 1647·2021-08-11 11:19
閱讀 883·2019-08-30 15:55
閱讀 821·2019-08-30 10:52
閱讀 2845·2019-08-29 13:11
閱讀 2924·2019-08-23 17:08
閱讀 2833·2019-08-23 15:11
閱讀 3066·2019-08-23 14:33