天天看點

詳解JavaScript垃圾回收機制

垃圾回收機制

JS的垃圾回收機制是為了以防記憶體洩漏,記憶體洩漏的含義就是當已經不需要某塊記憶體時這塊記憶體還存在着,垃圾回收機制就是間歇的不定期的尋找到不再使用的變量,并釋放掉它們所指向的記憶體。

var a = 'before'
var b = 'override a'
var a = b // 重寫a      

這段代碼運作之後,“before”這個字元串失去了引用(之前是被a引用),系統檢測到這個事實之後,就會釋放該字元串的存儲空間以便這些空間可以被再利用。

變量的生命周期

當一個變量的生命周期結束之後它所指向的記憶體就應該被釋放。JS有兩種變量,全局變量和在函數中産生的局部變量。局部變量的生命周期在函數執行過後就結束了,此時便可将它引用的記憶體釋放(即垃圾回收),但全局變量生命周期會持續到浏覽器關閉頁面

現在各大浏覽器通常用采用的垃圾回收有兩種方法:标記清除、引用計數。

标記清除

這是javascript中最常用的垃圾回收方式。當變量進入執行環境是,就标記這個變量為“進入環境”。從邏輯上講,永遠不能釋放進入環境的變量所占用的記憶體,因為隻要執行流進入相應的環境,就可能會用到他們。當變量離開環境時,則将其标記為“離開環境”。垃圾收集器在運作的時候會給存儲在記憶體中的所有變量都加上标記。然後,它會去掉環境中的變量以及被環境中的變量引用的标記。而在此之後再被加上标記的變量将被視為準備删除的變量,原因是環境中的變量已經無法通路到這些變量了。最後。垃圾收集器完成記憶體清除工作,銷毀那些帶标記的值,并回收他們所占用的記憶體空間。

引用計數

另一種不太常見的垃圾回收政策是引用計數。引用計數的含義是跟蹤記錄每個值被引用的次數。當聲明了一個變量并将一個引用類型指派給該變量時,則這個值的引用次數就是1。相反,如果包含對這個值引用的變量又取得了另外一個值,則這個值的引用次數就減1。當這個引用次數變成0時,則說明沒有辦法再通路這個值了,因而就可以将其所占的記憶體空間給收回來。這樣,垃圾收集器下次再運作時,它就會釋放那些引用次數為0的值所占的記憶體。

存在問題:

function problem() {
    var objA = new Object();
    var objB = new Object();

    objA.someOtherObject = objB;
    objB.anotherObject = objA;
}      

在這個例子中,objA和objB通過各自的屬性互相引用;也就是說這兩個對象的引用次數都是2。在采用引用計數的政策中,由于函數執行之後,這兩個對象都離開了作用域,函數執行完成之後,objA和objB還将會繼續存在,因為他們的引用次數永遠不會是0。這樣的互相引用如果說很大量的存在就會導緻大量的記憶體洩露。

IE中有一部分對象并不是原生JavaScript對象。例如,其BOM和DOM中的對象就是使用C++以COM(Component Object 

Model,元件對象)對象的形式實作的,而COM對象的垃圾回收器就是采用的引用計數的政策。是以,即使IE的Javascript引擎使用标記清除的政策來實作的,但JavaScript通路的COM對象依然是基于引用計數的政策的。說白了,隻要IE中涉及COM對象,就會存在循環引用的問題。看看下面的這個簡單的例子:

var element = document.getElementById("some_element");
var myObj =new Object();
myObj.element = element;
element.someObject = myObj;      
myObj.element = null;
element.someObject =null;      

繼續閱讀