《Javascript》- 垃圾回收機制


《Javascript》- 垃圾回收機制

回收機制

Javascript會找出已經用不上的變量,將其釋放,也就意味著該變量的聲明週期結束了。

但是Javascript有兩種變量,即全局變量和局部變量,全局變量卻不會被釋放,直至頁面關閉。

局部變量整個聲明週期,在函數內聲明開始,為其分配相應的堆或棧空間進行存儲,直至函數執行結束,變量也就不再使用,其佔用的空間也將被釋放。

上述情況,有個特殊情況會導致局部函數變量不會因為函數執行結束而被回收,就是局部變量被外部所調用(如閉包),函數雖然執行結束,但函數外部變量依然指向了該局部變量,仍然被使用,不能回收。

舉個例子:

<code>function func1() {
const makeit = 'https://blog.makeit.vip';
}
function func2() {
const makeit = 'https://mall.makeit.vip';
return makeit;
}
const m1 = func1();
const m2 = func2();

// 上述例子中,分別定義了 func1 與 func2 兩個函數

// func1 執行時為 makeit 變量分配了空間,執行完成後即釋放了
// func2 執行時,同樣也為 makeit 分配了空間,但 makeit 最後被返回後賦值給了 m2
// func2 執行完後,makeit 依然被使用中,導致 makeit 佔用的空間不會被釋放/<code>


實現方式

《Javascript》- 垃圾回收機制

1.標記清除

Javascript中常見的一種垃圾回收方式

當變量進入執行環境時,則該變量被標記為“進入環境”的狀態,原則上來講,“進入環境”的狀態是永遠不會被清除的,因為進入相應的執行環境後,該變量就隨時可能被調用到。當離開執行環境時,則被標記為“離開環境”的狀態

垃圾收集器會給存儲在內存中的所有變量都加上標記,緊接著會過濾出執行環境中的變量及在被環境中的變量所引用的變量(閉包),去掉這些變量後,剩下的就是待回收的變量了,因為環境中已經無法再訪問這些變量了,垃圾回收器則會回收這些變量值,回收這些變量值所佔的內存空間。


《Javascript》- 垃圾回收機制

2.引用計數

引用計數的策略就是跟蹤記錄每個值的使用次數

當生命一個變量並將一個引用類型的值賦值給該變量,則該值的引用次數 + 1

如果該值的結果變為另外一個,則該值的引用次數 - 1

當這個值的引用次數為 0 的時候,說明已經無法訪問該變量了,則垃圾回收器會在運行時回收那些引用次數為 0 的值所佔的空間

但是這種策略,有個循環引用的問題,容易引起內存洩漏,具體如下示例

<code>function makeit() {
let m1 = {};
let m2 = {};
m1.vip = m2;
m2.miit = m1;
}

// 上述例子中,m1 與 m2 的引用次數都為 2,在 [ 標記清除 ] 的策略中,沒問題,離開環境後即回收了
// 但在 [ 引用計數 ] 中就出現問題了,引用次數始終不為 0,則意味著垃圾回收器始終都不會回收,這也就造成了內存洩漏


// 再舉個例子:
// 該段代碼,乍一看,沒什麼問題,但是 elem.onclick 方法會引用外部環境中的變量,這自然也就包括了 elem
// 如果沒有最後的 elem = null 手動回收的話,就造成了內存洩漏
window.onload = function makeit() {
const elem = document.getElementById('makeit');
elem.onclick = function() {
// ...
}
// 手動回收
elem = null;
}/<code>
《Javascript》- 垃圾回收機制

3.觸發時間

什麼時候觸發垃圾回收器進行垃圾回收呢?

IE6有個回收觸發點,就是變量達到 256 個,對象 4096 個,或 64KB 的字符,滿足三種情況中的任何一種,都將觸發垃圾回收,但這又有個問題,如果當前腳本本身就需要這麼多的變量或對象,不就導致垃圾回收器一直在不間斷的工作狀態中了?

來,針對剛剛那個問題,IE7做了調整,觸發條件不固定,可以動態修改,默認初始值與IE6一致。


分享到:


相關文章: