详细解释 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+ 次浏览

开启您的职业生涯

完成课程后获得认证

开始学习
广告