详细说明JavaScript中的标记和扫描算法?

标记和扫描算法

Mark and Sweep算法会寻找“无法到达”的对象,而不是“不再需要”的对象。该算法是对引用计数算法的改进。

该算法实际上经历了3个重要步骤。

  •  根:根通常是代码中使用的全局变量。javascript中的窗口对象可以充当根。该算法使用全局对象根来查找对象是可到达还是不可到达。

  • 然后,该算法监视每个根及其子节点。监视时,根据提供的条件,某些可到达的对象会被标记,而其余无法到达的对象将不会被标记。

  •  未标记的对象(即不可达的对象)将被垃圾回收。 

标记相

在标记阶段,我们可以找到哪些元素被标记,哪些元素未被标记。假设如示例1所示,将属性“ hello”分配给对象“ obj1”。此算法使用的根全局对象可以到达obj1及其属性“ hello”。因此它已被标记。

示例1

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

假设为该对象分配一个空值,如例2所示。然后,新分配的“ null”将被标记,而先前分配的“ property hello”将被取消标记。因此,在标记阶段结束时,我们可以得出结论,标记为“ null”的对象已标记,标记为“ property 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中显式触发垃圾回收的过程。