详细解释 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 中显式触发垃圾收集。
广告