我們都知道JavaScript具有自動垃圾收集機制,這也就是說抗蠢,執(zhí)行環(huán)境會管理代碼執(zhí)行過程中使用的內(nèi)存举哟。
這種垃圾收集機制的原理很簡單:找出那些不再繼續(xù)使用的變量,然后釋放其占用的內(nèi)存迅矛。
垃圾收集器必須跟蹤那個變量有用哪個變量沒用妨猩,對于不再有用的變量打上標記,以備將來收回其占用的內(nèi)存秽褒。用于標識無用的策略可能會因?qū)崿F(xiàn)而異册赛,但具體到瀏覽器中的實現(xiàn),則通常有兩個策略震嫉。
一.標記清除
1.標記清除是JavaScript中最常用的垃圾收集方式森瘪。
2.當變量進入環(huán)境時,就將這個變量標記為“進入環(huán)境”票堵,當變量離開環(huán)境時扼睬,則將其標記為“離開環(huán)境”。
3.可以使用任何方式來標記變量悴势。
4.垃圾收集器在運行時候會給存儲在內(nèi)存中的所有變量都加上標記窗宇。然后,它會去掉環(huán)境中的變量以及被環(huán)境中引用的變量的標記特纤。而在此之后再被加上標記的變量將被視為準備刪除的變量军俊,因為環(huán)境中的變量已經(jīng)無法訪問到這些變量了。最后捧存,垃圾收集器完成內(nèi)存清除工作粪躬,銷毀那些帶標記的值并收回它們所占用的內(nèi)存空間 。
二.引用計數(shù)
另一種不太常用的垃圾收集策略叫做引用計數(shù)昔穴。
引用計數(shù)其實就是跟蹤記錄每個值被引用的次數(shù)镰官。
1.聲明一個變量并將引用類型值賦給改變量,這個值的引用次數(shù)為1吗货;
2.如果同一個值又被賦給另一個變量泳唠,則改引用次數(shù)加1;
3.如果包含對這個值引用的變量又取另一個值宙搬,該引用次數(shù)減1笨腥;
4.當這個值得 引用次數(shù)為0時拓哺,說明無法訪問這個值,將其占用的內(nèi)存空間收回脖母。
5.當垃圾收收集器 下次運行時士鸥,釋放引用次數(shù)為0的值所占用的內(nèi)存。
下面我們來看一個循環(huán)引用的栗子
function problem(){
var objectA = new Object();
var objectB = new Object();
objectA.someOtherObject = objectB;
objectB.anotherObject = objectA;
}
在這個例子 中镶奉,objectA和objectB通過各自屬性相互引用,也就是說崭放,這兩個對象的引用次數(shù)都是2哨苛。
當采用標記清除策略時,由于函數(shù)執(zhí)行完后币砂,兩個對象都離開了作用域建峭,這種相互引用不存在問題。
當采用引用計數(shù)策略時决摧,函數(shù)執(zhí)行完畢后亿蒸,但objectA和objectB依然存在,因為它們的引用次數(shù)永遠不會為0掌桩,假如這個函數(shù)被多次調(diào)用边锁,就會導致大量內(nèi)存得不到回收。
所以說波岛,引用計數(shù)策略會導致很多麻煩茅坛。
性能問題
垃圾收集器是周期性運行的,而且如果分配的內(nèi)存數(shù)量很客觀则拷,那么回收工作量也是相當大的贡蓖。
在這種情況下,確定垃圾收集的時間間隔是一個非常重要的問題煌茬。
JavaScript引擎的垃圾收集例程改變了工作方式:觸發(fā)垃圾收集的變量分配斥铺,字面量和數(shù)組元素的臨界值被調(diào)整為動態(tài)修正。
管理內(nèi)存
JavaScript在進行內(nèi)存管理及垃圾收集時面臨一個問題:分配給Web瀏覽器的可用內(nèi)存數(shù)量通常比分配給桌面應用程序的少坛善。
這樣做的目的是:防止運行JavaScript的網(wǎng)頁耗盡全部系統(tǒng)內(nèi)存而導致系統(tǒng)崩潰晾蜘。
解除引用:為了在執(zhí)行代碼時只保存必要的數(shù)據(jù),一旦數(shù)據(jù)不再有用眠屎,最好通過將其值設置為null來釋放其引用笙纤。
這一做法適用于大多數(shù)全局變量和全局對象的屬性。
局部變量會在它們離開執(zhí)行環(huán)境時自動被解除引用组力。
我們來看看下面的栗子:
function createPerson(name){
var localPerson = new Object();
localPerson.name = name;
return localPerson;
}
var globalPerson = createPerson("Jimmy");
//手工解除globalPerson的引用
globalPerson = null;
在這個例子中l(wèi)acalPerson是一個局部變量省容,它在createPerson()函數(shù)執(zhí)行完畢后就離開了執(zhí)行環(huán)境,不需要我們?nèi)樗獬茫琯lobalPerson是一個全部變量燎字,我們通過給它設null來手動解除腥椒。
解除一個值的引用并不意味著自動收回該值所占用的內(nèi)存阿宅,解除引用的真正作用是讓值脫離執(zhí)行環(huán)境,方便垃圾收集器器下次運行時將其收回笼蛛。