垃圾收集

wyfem發表於2021-09-09

我們都知道JavaScript具有自動垃圾收集機制,這也就是說,執行環境會管理程式碼執行過程中使用的記憶體。

這種垃圾收集機制的原理很簡單:找出那些不再繼續使用的變數,然後釋放其佔用的記憶體。

垃圾收集器必須跟蹤那個變數有用哪個變數沒用,對於不再有用的變數打上標記,以備將來收回其佔用的記憶體。用於標識無用的策略可能會因實現而異,但具體到瀏覽器中的實現,則通常有兩個策略。

一.標記清除

1.標記清除是JavaScript中最常用的垃圾收集方式。
2.當變數進入環境時,就將這個變數標記為“進入環境”,當變數離開環境時,則將其標記為“離開環境”。
3.可以使用任何方式來標記變數
4.垃圾收集器在執行時候會給儲存在記憶體中的所有變數都加上標記。然後,它會去掉環境中的變數以及被環境中引用的變數的標記。而在此之後再被加上標記的變數將被視為準備刪除的變數,因為環境中的變數已經無法訪問到這些變數了。最後,垃圾收集器完成記憶體清除工作,銷燬那些帶標記的值並收回它們所佔用的記憶體空間 。

二.引用計數

另一種不太常用的垃圾收集策略叫做引用計數
引用計數其實就是跟蹤記錄每個值被引用的次數。
1.宣告一個變數並將引用型別值賦給改變數,這個值的引用次數為1;
2.如果同一個值又被賦給另一個變數,則改引用次數加1;
3.如果包含對這個值引用的變數又取另一個值,該引用次數減1;
4.當這個值得 引用次數為0時,說明無法訪問這個值,將其佔用的記憶體空間收回。
5.當垃圾收收集器 下次執行時,釋放引用次數為0的值所佔用的記憶體。

下面我們來看一個迴圈引用的栗子

function problem(){    var  objectA = new Object();    var  objectB = new Object();
                
    objectA.someOtherObject = objectB;
    objectB.anotherObject = objectA;
}

在這個例子 中,objectA和objectB透過各自屬性相互引用,也就是說,這兩個物件的引用次數都是2。

當採用標記清除策略時,由於函式執行完後,兩個物件都離開了作用域,這種相互引用不存在問題。

當採用引用計數策略時,函式執行完畢後,但objectA和objectB依然存在,因為它們的引用次數永遠不會為0,假如這個函式被多次呼叫,就會導致大量記憶體得不到回收。

所以說,引用計數策略會導致很多麻煩。

效能問題

垃圾收集器是週期性執行的,而且如果分配的記憶體數量很客觀,那麼回收工作量也是相當大的。
在這種情況下,確定垃圾收集的時間間隔是一個非常重要的問題。

JavaScript引擎的垃圾收集例程改變了工作方式:觸發垃圾收集的變數分配,字面量和陣列元素的臨界值被調整為動態修正。

管理記憶體

JavaScript在進行記憶體管理及垃圾收集時面臨一個問題:分配給Web瀏覽器的可用記憶體數量通常比分配給桌面應用程式的少。
這樣做的目的是:防止執行JavaScript的網頁耗盡全部系統記憶體而導致系統崩潰。
解除引用:為了在執行程式碼時只儲存必要的資料,一旦資料不再有用,最好透過將其值設定為null來釋放其引用。
這一做法適用於大多數全域性變數和全域性物件的屬性。
區域性變數會在它們離開執行環境時自動被解除引用。

我們來看看下面的栗子:

function createPerson(name){    var localPerson = new Object();
    localPerson.name = name;    return localPerson;
}var globalPerson = createPerson("Jimmy");//手工解除globalPerson的引用globalPerson = null;

在這個例子中lacalPerson是一個區域性變數,它在createPerson()函式執行完畢後就離開了執行環境,不需要我們去為它解除引用,globalPerson是一個全部變數,我們透過給它設null來手動解除。

解除一個值的引用並不意味著自動收回該值所佔用的記憶體,解除引用的真正作用是讓值脫離執行環境,方便垃圾收集器器下次執行時將其收回。



作者:Passerbylll
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2894/viewspace-2812551/,如需轉載,請註明出處,否則將追究法律責任。

相關文章