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