簡單梳理JavaScript垃圾回收機制

JavaScript具有自動垃圾回收機制,即執行環境會負責管理代碼執行過程中使用地內存。

這種垃圾回收機制的原理很簡單:找出那些不再繼續使用的變量,然後釋放其佔用的內存。爲此,垃圾收集器會按照固定的時間間隔(或代碼執行中預定的收集時間)週期性地執行這一操作。

對於函數中局部變量來說,其只在函數的執行過程中存在,在這個過程中,會爲局部變量在堆(或棧)內存上分配相應的空間,以便存儲它們的值。然後在函數中使用這些變量,直至函數結束。此時局部變量沒有存在的必要了,可以釋放其內存。在這種情況下,容易判斷變量是否還有存在的必要,但是並非所有情況下都這麼容易得出結論。垃圾收集器必須跟蹤哪個變量有用哪個變量沒用,對於不再有用的變量打上標記,以備將來收回其佔用的內存。用於標識無用變量的策略具體到瀏覽器中的實現,通常有兩個策略。

  • 標記清除
  • 引用計數

1. 標記清除

標記清除是JavaScript中最常用的垃圾收集方式。當變量進入環境(例如在函數中聲明一個變量)時,就將這個變量標記爲“進入環境”。邏輯上講,永遠不能釋放進入環境的變量所佔用的內存。因爲只要執行流進入相應的環境,就可能會用到它們。當變量離開環境時,則將其標記爲“離開環境”。

可以使用任何方式標記變量,如何標記變量並不重要,關鍵是採用何種策略。垃圾收集器在運行得時候會給存儲在內存中得所有變量都加上標記。然後,它會去掉環境中的變量及被環境中的變量引用的變量的標記。而在此之後再次被加上標記的變量將被視爲準備刪除的變量(環境中的變量已經無法訪問到這些變量)。最後,垃圾收集器完成內存清除工作,銷燬那些帶標記的值並回收它們所佔用的空間。

2. 引用計數

引用計數是另一種不太常見的垃圾收集策略。引用計數的含義是跟蹤記錄每個值被引用的次數。當聲明瞭一個變量並將一個引用類型值賦給該變量時,則這個值的引用次數就是1.如果同一個值又被賦給另一個變量,則該值的引用次數加1.相反,如果包含對這個值引用的變量又取得了另外一個值,則這個值的引用次數減1.當這個值得引用次數變成0時,則說明沒有辦法再訪問這個值了。因此將其佔用得空間回收回來。這樣,當垃圾收集器下次再運行時,它就會釋放那些引用次數爲零得值所佔用的內存。

Netscape Navigator 3.0是最早使用計數策略的瀏覽器,但很快就遇到一個嚴重的問題:循環引用。循環引用指:對象A中包含一個指向對象B的指針,而對象B也包含一個指向對象A的引用。它們的引用次數永遠不會是0。循環引用將導致內存無法回收

需要知道的是,IE中有部分對象不是原生JavaScript對象。例如,BOM和DOM中的對象就是使用C++以COM對象的形式實現的,而COM對象的垃圾收集機制採用的就是引用計數策略。因此,即使IE的JavaScript引擎使用標記清除策略實現,但是JavaScript訪問的COM對象依然基於引用計數策略。換句話說,只要在IE中涉及COM對象,就會存在循環引用的問題(IE9將BOM和DOM對象都轉換爲真正的JavaScript對象,避免了兩種垃圾收集算法並存導致的問題,也消除了常見的內存泄露現象)。

爲避免類似的循環引用問題,最好在不適用它們的時候手工斷開原生JavaScript對象與DOM元素之間的連接。

myObject.element = null;
element.someObj = null;

3. 小結

本文主要是爲了梳理JS垃圾回收機制所寫,闡述了JS垃圾回收機制的原理以及標記無用變量的策略(引用計數和標記清除),希望也能給小夥伴帶來幫助,梳理自己的知識體系。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章