JavaScript 垃圾回收機制:理解 Mark and Sweep 演算法與記憶體管理
此文章是 FrontendMaster 上的 Advanced Web Development Quiz 課程筆記
題目
閱讀以下程式碼,選出正確的敘述
javascript
function addMember(name) {
return { name, createdAt: Date.now() };
}
let obj1 = addMember('John');
let obj2 = addMember('Sarah');
obj1.friend = obj2;
obj2.friend = obj1;
obj1 = null;
obj2 = null;[1] obj1 and obj2 objects will not be garbage collected, leading to a memory leak.
[2] obj1 and obj2 objects will be garbage collected immediately after setting them to null.
[3] obj1 and obj2 will only be garbage collected after closing the brower tab.
[4] obj1 and obj2 objects can be garbage collected during the next garbage collection cycle.記憶體管理
所有的程式語言都會有記憶體管理的議題,尤其是低階語言開發者更需要了解,因為他們必須主動管理記憶體,然而像 JavaScript 這種高階語言在底層會自動釋放不會在使用的記憶體空間 ,稱為垃圾回收機制 (Garbage Collection),所以開發者不太需要特別在意也可以自由撰寫程式
垃圾回收機制 Garbage Collection
- JavaScript 在程式執行階段把變數與物件儲存在記憶體 (heap memory) 中
- JavaScript 引擎追蹤使用中的物件與變數,未被使用的就是無法觸及的 (unreachable)
- 無法觸及的物件在被自動偵測到號會透過垃圾回收機制從記憶體中移除
- 垃圾回收機制在背景中執行,定期移除不再使用的物件來釋放記憶體
- 自動處理,開發者不需要手動管理記憶體
heap: 專門搜集執行期間動態產生的資料
垃圾回收機制背後的演算法 - Mark and Sweep
這是現在所有 JavaScript 引擎應該都在使用的演算法
這一套演算法可以找到無法觸及 (unreachable) 的物件,並將其自記憶體中移除
在 JavaScript 中會以全域物件作為根物件作為起點,尋找所有其參考的物件,再從這些物件尋找其參考的所有物件,以此類推,把所有觸及的物件標記起來,就可以把未被標記的物件視為無法觸及的物件,最後從記憶體中清除。
javascript
let obj1 = { name: 'Object 1' };
let obj2 = { name: 'Object 2' };
obj1 = null;
console.log(obj1);從這一段的程式碼可以發現 obj1 原先參考的 { name: "Object 1" } 物件在最後變成孤兒了,所以 JavaScript 引擎就會把這個物件的記憶體清除,然而 { name: "Object 2" } 因為還有被 obj2 參考,所以並不會被清除。
參考技術垃圾回收 Reference-counting garbage collection
這是早期的 JavaScript 所使用的演算法,目前已經沒有使用了
這套演算法的機制是:判斷物件是否仍有被其他物件引用,如果沒有參考任何其他物件就會被視為要被清除的物件。
這個機制的問題在於,假設兩個物件有相互參考,形成一個循環參考的狀況,此時即便這兩個物件都不可能再被拿去使用了,仍然會留在記憶體中,造成記憶體的洩漏 (memory leaks)
開發者需要避免的
雖然前面說開發者不用特別注意,但還是有一些情況我們必須要注意的做法,否則仍然會造成記憶體浪費的問題
- 避免過度使用全域變數:使用
let&const,避免使用var來創造出全域變數 - 當元素被移除時,也要移除其綁定的事件監聽
- 清除未被觸發的 interval & timeout
- 當物件不再使用時可以把參考此物件的變數指定為
null - 注意閉包的使用:有時候可能不小心在閉包裡面存了一大包物件
答案
[4] obj1 and obj2 objects can be garbage collected during the next garbage collection cycle.