相对于引用计数来说,标记清除算法的原理实现更加简单。而且还能解决一些相应的问题,在 V8 当中它会被大量的使用到。对于标记清除算法来说,它的核心思想就是:将整个垃圾回收操作分成两个阶段来完成。
第一个阶段他会去遍历所有的对象,然后找到这些活动对象进行标记的操作。这里的活动对象和之前所提到的可达对象是一个道理;
第二个阶段,仍然回去遍历所有的对象然后把那些身上没有标记的对象进行清除。同时需要注意的就是在第二阶段当中它也会把第一个阶段所设置的标记给抹掉,便于 GC 下次还能够去正常的工作,这样一来的话它就可以去通过两次的遍历行为,把当前这样一个垃圾空间去进行回收最终在交给相应的空闲列表进行维护。
这就是标记清除算法的实现原理,其实就是两个操作:第一就是标记、第二就是做清除。为了方便理解下面用图示做举例说明:在全局的地方我们可以找到 A、B、C 这样的三个可达对象。找到这三个可达对象之后,会发现它的下边还会有一些子引用,所以这就是标记清除算法强大的地方。如果我们发现它的下面会有还在甚至于说孩子的孩子,这个时候它会去用递归的方式继续寻找那些可达的对象,如图中的 D、E 也会被做可达的标记。那么这个时候图中的 a1、b1 放在右侧它可能是由于我们当前放在了一个局部作用域,而当前这个作用域执行完成以后这样一个空间就被回收了。所以从当前 global 这样一个链条下我们是找不到 a1、b1 的。这个时候 GC 机制就会认为它是一个垃圾对象,没有去给他做标记,最终呢在我们 GC 去工作的时候就会找到 a1、b1 然后直接把它们回收掉。这就是标记清除的标记阶段和清除阶段要做的事情,简单的整理一下就是分成两个步骤:在第一个阶段当中我们要去找到所有可达对象,如果说在这里涉及到了我们这样应用的一个层次关系,那么它回去递归的进行查找。就想图中的 global 找 A 再找 D 这样一个过程。找完以后它会将这些可达对象都进行标记,标记完成以后会进行第二个阶段。然后会开始做清除,找到那些没有去做标记的对象。同时呢还会将之前第一次所做的标记也给它清除掉,这样我们就完成了一次垃圾的回收。同时呢我们还要好留意最终它还会去把回收的空间直接放在当前的和一个叫做空闲列表上面,方便我们后面的程序可以直接在这去申请空间使用。
这一块就是关于标记清除算法的实现原理