本文主要介绍标准的标记-清除算法的过程,优缺点,以及做的一些优化过程。
GC Mark-Sweep Algorithm
1.GC标记清除算法
标记清除算法主要分为两个阶段:标记、清除。
标记阶段:将所有的活动对象做上标记;
清除阶段:把内存里面没有打上标记的对象回收掉。
通过这两个阶段,就可以把不需要的空间重复利用。
下面详细介绍一下标记阶段和清除阶段是怎么做的。
假设现在执行GC前有一块分块堆状态如下图:
1.1 标记阶段
标记阶段的伪代码如下:
mark_phase(){
for(r : $roots) {
mark(*r)
}
}
collector从遍历所有的根节点出发,标记所有的活动对象。然后通过调用递归函数mark()函数,mark函数伪代码如下:
mark(obj){
if(obj.mark == FALSE){ //对象没有被标记
//设置对象是活动对象
obj.mark = TRUE
for(child : children(obj)){ // 递归对象的子节点
mark(*child)
}
}
第二行判断 if(obj.mark == FALSE)
主要是针对循环引用的场景,避免循环引用时候会循环调用mark函数,避免重复进行标记处理。
这个标记obj.mark 肯定是需要保存到对象的头里面。
标记完所有活动对象后,标记阶段就结束了。标记阶段结束后堆的状态如下图: