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