標籤:記憶體回收 ima 個數 類型 記憶體回收機制 編程 other 垃圾收集 沒有
什麼是記憶體泄露?
任何程式設計語言,在運行時都需要使用到記憶體,比如在一個函數中, var arr = [1, 2, 3, 4, 5]; 這麼一個數組,就需要記憶體。
但是,在使用了這些記憶體之後, 如果後面他們不會再被用到,但是還沒有及時釋放,這就叫做記憶體泄露(memory leak)。如果出現了記憶體泄露,那麼有可能
C語言是通過手動分配和釋放記憶體的, 如通過malloc分配,通過free釋放,這種方式是比較麻煩的。而java、c#、js等是為瞭解放程式員的負擔,提出了程式自動釋放記憶體,這種方式就是記憶體回收機制。
JavaScript中的兩種記憶體回收機制
在js中,有引用計數和標記清除這兩種記憶體回收機制。
引用計數
即追蹤記錄每個值被引用的次數,當聲明了一個變數並將一個參考型別賦值給該變數時,則這個值的引用次數就是1; 相反,如果包含對這個值引用的變數又取得了另外一個值,那麼這個值的引用次數就減1;當引用次數變為0的時候,則說明沒有辦法再訪問到這個值了,所以,就可以把其所佔用的記憶體空間給收回來。 這樣,垃圾收集器下次再運行時,他就會釋放哪些引用次數為0的值所佔的記憶體。
但是,引用計數還是會存在問題的:
function problem() { var objA = new Object(); var objB = new Object(); objA.someOtherObject = objB; objB.anotherObject = objA;}
如上所示,objA指向記憶體中的參考型別,而這個參考型別的一個值又指向了另一個參考型別,這樣,每個參考型別的引用次數都是2,且在參考型別之間形成了循環參考,這樣,即使problem()函數執行完畢,把後期不再使用的局部變數objA和objB釋放,但是因為參考型別的引用次數還是1,那麼這兩個參考型別還是不能被釋放的,這就造成了記憶體泄露。 如所示:
所以說,我們所說的循環參考實際上是在堆中的兩個參考型別之間的循環參考,如右邊的兩個箭頭就構成了一個迴圈。
另外,由於BOM和DOM中的對象是使用C++以COM(Component Ojbect Model,組件對象)對象的形式實現的,而COM對象的記憶體回收機制是引用計數。 因此,即使IE的JavaScript引擎使用的是標記清除的策略,但是JavaScript訪問的COM對象依然是基於引用計數的策略的,說白了,只要IE中涉及到了COM對象,就會存在循環參考的問題。 如下:
var element = document.getElementById("some_element");var myObj =new Object();myObj.element = element;element.someObject = myObj;
這個例子中,一個DOM元素和一個原生JavaScript對象之間建立了循環參考。這樣,即使例子中的DOM從頁面中移除,記憶體也不會被回收,但是,我們可以手動切斷他們的循環參考:
myObj.element = null;element.someObject =null;
這樣寫代碼就可以解決循環參考的問題,也就防止了記憶體泄露的問題了。
標記清除
這是JavaScript中最常用的記憶體回收機制。當變數進入環境時,就標記這個變數為“進入環境”,邏輯上說,永遠不能釋放進入環境的變數所佔用的記憶體,因為一旦進入環境就有可能隨時用到他們,當變數離開環境的時候,將其標記為“離開環境”。
區別:可以看到,引用計數是即時的,即只要引用數為0,就會清除這變數,而標記清除是添加上標記之後,每隔一段時間回收哪些添加了離開環境標記的變數。
使用方式:不同的瀏覽器可能採用的回收機制不同,比如有的可能全部使用引用計數,有的全部使用標記清除。 但是,BOM、DOM採用的一定都是引用計數。
JavaScript中的記憶體回收機制與記憶體泄露