垃圾收集

我們都知道JavaScript具有自動(dòng)垃圾收集機(jī)制,這也就是說(shuō),執(zhí)行環(huán)境會(huì)管理代碼執(zhí)行過(guò)程中使用的內(nèi)存。

這種垃圾收集機(jī)制的原理很簡(jiǎn)單:找出那些不再繼續(xù)使用的變量,然后釋放其占用的內(nèi)存。

垃圾收集器必須跟蹤那個(gè)變量有用哪個(gè)變量沒(méi)用,對(duì)于不再有用的變量打上標(biāo)記,以備將來(lái)收回其占用的內(nèi)存。用于標(biāo)識(shí)無(wú)用的策略可能會(huì)因?qū)崿F(xiàn)而異,但具體到瀏覽器中的實(shí)現(xiàn),則通常有兩個(gè)策略。

一.標(biāo)記清除

1.標(biāo)記清除是JavaScript中最常用的垃圾收集方式。
2.當(dāng)變量進(jìn)入環(huán)境時(shí),就將這個(gè)變量標(biāo)記為“進(jìn)入環(huán)境”,當(dāng)變量離開(kāi)環(huán)境時(shí),則將其標(biāo)記為“離開(kāi)環(huán)境”。
3.可以使用任何方式來(lái)標(biāo)記變量。
4.垃圾收集器在運(yùn)行時(shí)候會(huì)給存儲(chǔ)在內(nèi)存中的所有變量都加上標(biāo)記。然后,它會(huì)去掉環(huán)境中的變量以及被環(huán)境中引用的變量的標(biāo)記。而在此之后再被加上標(biāo)記的變量將被視為準(zhǔn)備刪除的變量,因?yàn)榄h(huán)境中的變量已經(jīng)無(wú)法訪問(wèn)到這些變量了。最后,垃圾收集器完成內(nèi)存清除工作,銷(xiāo)毀那些帶標(biāo)記的值并收回它們所占用的內(nèi)存空間 。

二.引用計(jì)數(shù)

另一種不太常用的垃圾收集策略叫做引用計(jì)數(shù)。
引用計(jì)數(shù)其實(shí)就是跟蹤記錄每個(gè)值被引用的次數(shù)。
1.聲明一個(gè)變量并將引用類(lèi)型值賦給改變量,這個(gè)值的引用次數(shù)為1;
2.如果同一個(gè)值又被賦給另一個(gè)變量,則改引用次數(shù)加1;
3.如果包含對(duì)這個(gè)值引用的變量又取另一個(gè)值,該引用次數(shù)減1;
4.當(dāng)這個(gè)值得 引用次數(shù)為0時(shí),說(shuō)明無(wú)法訪問(wèn)這個(gè)值,將其占用的內(nèi)存空間收回。
5.當(dāng)垃圾收收集器 下次運(yùn)行時(shí),釋放引用次數(shù)為0的值所占用的內(nèi)存。

下面我們來(lái)看一個(gè)循環(huán)引用的栗子

function problem(){
    var  objectA = new Object();
    var  objectB = new Object();
                
    objectA.someOtherObject = objectB;
    objectB.anotherObject = objectA;
}

在這個(gè)例子 中,objectA和objectB通過(guò)各自屬性相互引用,也就是說(shuō),這兩個(gè)對(duì)象的引用次數(shù)都是2。

當(dāng)采用標(biāo)記清除策略時(shí),由于函數(shù)執(zhí)行完后,兩個(gè)對(duì)象都離開(kāi)了作用域,這種相互引用不存在問(wèn)題。

當(dāng)采用引用計(jì)數(shù)策略時(shí),函數(shù)執(zhí)行完畢后,但objectA和objectB依然存在,因?yàn)樗鼈兊囊么螖?shù)永遠(yuǎn)不會(huì)為0,假如這個(gè)函數(shù)被多次調(diào)用,就會(huì)導(dǎo)致大量?jī)?nèi)存得不到回收。

所以說(shuō),引用計(jì)數(shù)策略會(huì)導(dǎo)致很多麻煩。

性能問(wèn)題

垃圾收集器是周期性運(yùn)行的,而且如果分配的內(nèi)存數(shù)量很客觀,那么回收工作量也是相當(dāng)大的。
在這種情況下,確定垃圾收集的時(shí)間間隔是一個(gè)非常重要的問(wèn)題。

JavaScript引擎的垃圾收集例程改變了工作方式:觸發(fā)垃圾收集的變量分配,字面量和數(shù)組元素的臨界值被調(diào)整為動(dòng)態(tài)修正。

管理內(nèi)存

JavaScript在進(jìn)行內(nèi)存管理及垃圾收集時(shí)面臨一個(gè)問(wèn)題:分配給Web瀏覽器的可用內(nèi)存數(shù)量通常比分配給桌面應(yīng)用程序的少。
這樣做的目的是:防止運(yùn)行JavaScript的網(wǎng)頁(yè)耗盡全部系統(tǒng)內(nèi)存而導(dǎo)致系統(tǒng)崩潰。
解除引用:為了在執(zhí)行代碼時(shí)只保存必要的數(shù)據(jù),一旦數(shù)據(jù)不再有用,最好通過(guò)將其值設(shè)置為null來(lái)釋放其引用。
這一做法適用于大多數(shù)全局變量和全局對(duì)象的屬性。
局部變量會(huì)在它們離開(kāi)執(zhí)行環(huán)境時(shí)自動(dòng)被解除引用。

我們來(lái)看看下面的栗子:

function createPerson(name){
    var localPerson = new Object();
    localPerson.name = name;
    return localPerson;
}
var globalPerson = createPerson("Jimmy");
//手工解除globalPerson的引用
globalPerson = null;

在這個(gè)例子中l(wèi)acalPerson是一個(gè)局部變量,它在createPerson()函數(shù)執(zhí)行完畢后就離開(kāi)了執(zhí)行環(huán)境,不需要我們?nèi)樗獬?,globalPerson是一個(gè)全部變量,我們通過(guò)給它設(shè)null來(lái)手動(dòng)解除。

解除一個(gè)值的引用并不意味著自動(dòng)收回該值所占用的內(nèi)存,解除引用的真正作用是讓值脫離執(zhí)行環(huán)境,方便垃圾收集器器下次運(yùn)行時(shí)將其收回。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容