垃圾回收機制——總結自《JavaScript高級程序設計》

垃圾收集(garbage collection)

在編寫 JavaScript 程序時,開發人員不用再關心內存使用問題,所需內存的分配以及無用內存的回收徹底實現了自動管理。這種垃圾收集機制的原理其實很簡單:找出那些再也不繼續使用的變量,而後釋放其佔用的內存。爲此,垃圾收集器會按照固定的時間間隔(或代碼執行中預約的收集時間),週期性地執行這一操做。算法

垃圾收集器必須跟蹤哪一個變量有用哪一個變量沒用,對於再也不有用的變量打上標記,以備未來收回其佔用的內存。用於標識無用變量的策略可能會因實現而異,但具體到瀏覽器中的實現,則一般有兩個策略:標記清除和引用計數瀏覽器

標記清除(mark-and-sweep)

垃圾收集器在運行的時候會給存儲在內存中的全部變量都加上標記(固然,可使用任何標記方式)。而後,它會去掉環境中的變量以及被環境中的變量引用的變量的標記。而在此以後再被加上標記的變量將被視爲準備刪除的變量,緣由是環境中的變量已經沒法訪問到這些變量了。最後,垃圾收集器完成內存清除工做,銷燬那些帶標記的值並回收它們所佔用的內存空間。函數

到 2008 年爲止, IE、 Firefox、 Opera、 Chrome 和 Safari 的 JavaScript 實現使用的都是標記清除式的垃圾收集策略(或相似的策略),只不過垃圾收集的時間間隔互有不一樣。code

引用計數(reference counting)

當聲明瞭一個變量並將一個引用類型值賦給該變量時,則這個值的引用次數就是 1。若是同一個值又被賦給另外一個變量,則該值的引用次數加 1。相反,若是包含對這個值引用的變量又取得了另一個值,則這個值的引用次數減 1。當這個值的引用次數變成 0 時,則說明沒有辦法再訪問這個值了,於是就能夠將其佔用的內存空間回收回來。這樣,當垃圾收集器下次再運行時,它就會釋放那些引用次數爲零的值所佔用的內存。對象

但在採用引用計數策略的實現中,當函數執行完畢後,函數內部循環引用的對象還將繼續存在,由於它們的引用次數永遠不會是 0。假如這個函數被重複屢次調用,就會致使大量內存得不到回收。正是因爲這個緣由,Netscape在Navigator 4.0中放棄了引用計數方式,轉而採用垃圾回收。ip

//循環引用實例
function problem(){
var objectA = new Object();
var objectB = new Object();
objectA.someOtherObject = objectB;
objectB.anotherObject = objectA;
}

IE 中有一部分對象並非原生 JavaScript 對象。例如,其 BOM 和 DOM 中的對象就是使用 C++以 COM(Component Object Model,組件對象模型)對象的形式實現的,而 COM 對象的垃圾收集機制採用的就是引用計數策略。所以,即便 IE 的 JavaScript 引擎是使用標記清除策略來實現的,但JavaScript 訪問的 COM 對象依然是基於引用計數策略的。換句話說,只要在 IE 中涉及 COM 對象,就會存在循環引用的問題。爲了不相似這樣的循環引用問題,最好是在不使用它們的時候手工斷開原生 JavaScript 對象與DOM 元素之間的鏈接(賦值爲null)。
IE9 把 BOM 和 DOM 對象都轉換成了真正的 JavaScript 對象。這樣,就避免了兩種垃圾收集算法並存致使的問題,也消除了常見的內存泄漏現象。內存

總結:內存的自動回收基於兩種策略:其中的引用計數策略在對象循環引用時不可用,IE8及如下的DOM和BOM對象操做深受其害;目前,IE9+和其餘四大瀏覽器基本支持標記清除方式,區別僅在於垃圾回收的週期不一樣。開發

相關文章
相關標籤/搜索