關於JS垃圾回收機制

一、垃圾回收機制的必要性

       由於字元串、對象和數組沒有固定大小,所以當它們的大小已知時,才能對它們進行動態的存儲分配。JavaScript程式每次創建字元串、數組或對象時,解釋器都必須分配記憶體來存儲那個實體。只要像這樣動態地分配了記憶體,最終都要釋放這些記憶體以便它們能夠被再用,否則,JavaScript的解釋器將會消耗完系統中所有可用的記憶體,造成系統崩潰。

  JavaScript的解釋器可以檢測到何時程式不再使用一個對象了,當它確定了一個對象是無用的時候,它就知道不再需要這個對象,可以把它所佔用的記憶體釋放掉了。

二、垃圾回收機制

  Js具有自動垃圾回收機制。垃圾收集器會按照固定的時間間隔周期性的執行。

1、標記清除(常用) 

  當一塊記憶體中的數據能夠被訪問時,垃圾回收器就認為”該數據能夠被獲得”。不能夠被獲得的數據,就會被打上標記,並回收記憶體空間。這種方式叫作標記—清除演算法。

這個演算法會設置一個全局對象,並定期地從全局對象開始查找,垃圾回收器會找到所有可以獲得與不能獲得的數據。

  工作流程:

   (1)垃圾回收器,在運行的時候會給存儲在記憶體中的所有變數都加上標記。

   (2)去掉環境中的變數以及被環境中的變數引用的變數的標記。

   (3)再被加上標記的會被視為準備刪除的變數。

   (4)垃圾回收器完成記憶體清除工作,銷毀那些帶標記的數據並回收它們所佔用的記憶體空間。

  注意:在局部作用域中,當函數執行完畢後,局部變數也就沒有存在的必要了,因此垃圾收集器很容易做出判斷並回收。但在全局中,變數什麼時候需要自動釋放記憶體空間則很難判斷,因此我們在開發時,應盡量避免使用全局變數。如果使用了全局變數,則建議不再使用它時,通過釋放變數方式,以確保能夠及時回收記憶體空間。

2、引用計數

  跟蹤記錄每個值被引用的次數。例當變數聲明,第一次賦值時記為1,然後當這個變數值改變時,記錄為0,將計數為0的回收。

  工作流程:

   (1)聲明了一個變數並將一個引用類型的值賦值給這個變數,這個引用類型值的引用次數就是1。

   (2)同一個值又被賦值給另一個變數,這個引用類型值的引用次數加1.

   (3)當包含這個引用類型值的變數又被賦值成另一個值了,那麼這個引用類型值的引用次數減1.

   (4)當引用次數變成0時,說明沒辦法訪問這個值了。

   (5)當垃圾收集器下一次運行時,它就會釋放引用次數是0的值所佔的記憶體。  

但是當循環引用的時候就會釋放不掉記憶體。

1 function problem() {
2     var objA = new Object();
3     var objB = new Object();
4 
5     objA.someOtherObject = objB;
6     objB.anotherObject = objA;
7 }

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

因為IE中的BOM、DOM的實現使用了COM,而COM對象使用的垃圾收集機制是引用計數策略。所以會存在循環引用的問題。

解決:手工斷開js對象和DOM之間的鏈接,賦值為null。IE9把DOM和BOM轉換成真正的JS對象了,所以避免了這個問題。

 

Tags: