詳細解釋 JavaScript 中的 Mark and Sweep 演算法?


Mark and Sweep 演算法

Mark and Sweep 演算法尋找的是“不可達”的物件,而不是“不再需要”的物件。該演算法是對引用計數演算法的改進。

該演算法實際上包含三個重要步驟。

  • 根:一般來說,根是程式碼中使用的全域性變數。JavaScript 中的視窗物件可以充當根。該演算法使用全域性物件根來查詢物件是可達的還是不可達的。
  • 然後,該演算法監控每個根及其子物件。監控過程中,根據提供的條件,一些可達的物件會被標記,而其餘不可達的物件則不會被標記。
  • 未標記的物件,即不可達的物件將被垃圾收集。

標記階段

在標記階段,我們可以找到哪些元素被標記,哪些元素未被標記。假設我們將屬性“hello”賦值給物件“obj1”,如示例 1 所示。該演算法使用的根(全域性物件)可以訪問 obj1 及其屬性“hello”。因此,它現在被標記了。

示例-1

var obj1 = {
pro1: "hello" // marked because it can be reached by root.
}

假設將此物件賦值為 null 值,如示例 2 所示。然後,新賦值的“null”將被標記,而先前賦值的“屬性 hello”將被取消標記。因此,在標記階段結束時,我們可以得出結論:賦值為“null”的物件被標記,而賦值為“屬性 hello”的物件未被標記。

示例-2

obj1 = null // null will be marked(reachable) and hello will be unmarked(unreachable)

清除階段

顧名思義,它“清除”不可達的物件。在標記階段,我們看到帶有“屬性 hello”的物件未被標記,使其不可達。由於不可達的物件將被垃圾收集,因此此階段將垃圾收集帶有“屬性 hello”的物件。

Mark and Sweep 演算法也稱為追蹤式垃圾收集器,因為它追蹤程式直接或間接可訪問的整個物件集合。

迴圈不再是問題

在下面的示例中,當函式呼叫返回時,兩個物件 obj1 和 obj2 並沒有被可達的內容引用,因此有資格進行垃圾收集。因此,垃圾收集器將釋放物件 obj1 和 obj2 的記憶體。

示例

function f() {
   var obj1 = {};
   var obj2 = {};
   obj1.p = obj2; // obj1 references obj2
   obj2.p = obj1; // obj2 references obj1. This creates a cycle.
}
f();

侷限性

有時手動決定何時以及釋放哪些記憶體非常方便。為了釋放物件的記憶體,必須將其明確地設為不可達。目前,無法在 JavaScript 中顯式觸發垃圾收集。

更新於:2020年7月4日

1K+ 次瀏覽

開啟您的職業生涯

完成課程後獲得認證

開始學習
廣告
© . All rights reserved.