【GC Algorithm】标记消除算法
(此文章参考位置-21TO)
【概述】
标记-清除(Mark-Sweep)算法依赖于对所有存活对象进行一次全局遍历来确定哪些对象可以回收,遍历的过程从根出发,找到所有可达对象,除此之外,其它不可达的对象就是垃圾对象,可被回收。整个过程分为两个阶段:标记阶段找到所有存活对象;清除阶段清除所有垃圾对象。
标记-清除算法的执行过程是这样的:
午餐过程中,餐厅里的所有人都根据自己的需要取用餐巾纸。当垃圾收集机器人想收集废旧餐巾纸的时候,它会让所有用餐的人先停下来,然后,依次询问餐厅里的每一个人:“你正在用餐巾纸吗?你用的是哪一张餐巾纸?”机器人根据每个人的回答将人们正在使用的餐巾纸画上记号。询问过程结束后,机器人在餐厅里寻找所有散落在餐桌上且没有记号的餐巾纸(这些显然都是用过的废旧餐巾纸),把它们统统扔到垃圾箱里。 |
【优点】
1.标记-清除算法可以非常自然的处理环形引用问题
2.另外在创建对象和销毁对象时时少了操作引用计数值的开销
【缺点】
1.标记-清除算法是一种“停止-启动”算法,在垃圾回收器运行过程中,应用程序必须暂时停止
2.标记-清除算法在标记阶段需要遍历所有的存活对象,会造成一定的开销,在清除阶段,清除垃圾对象后会造成大量的内存碎片
【个人评论】
其实对于Mark-Sweep算法,一般的研究GC工作者而言,都十分熟悉。源于其普及度很高,大部分的GC算法皆是由该算法衍生。而这个算法本人觉得最大难点在于理解上。特别是理解根集合这个概念:
根集的概念:在程序运行的任意状态,寄存器(考虑多核CPU在多线程下),程序栈,和静态数据段中所有的指针的集合叫根集。
而在于我的理解,即是所以的指针集合。而问题出现了:你如何保存这些根指针?指针的类型是各种各样的,如果要统一保存这种跟指针,我想到是两种方法(针对c++):1.泛型;2.代理模式(智能指针)。不同的指针也只有将其转化为同一种指针才可能进行存储!
在java中其实是很容易实现,由于其采用单根继承模式。而c++同样可以建立一个独立框架,采用单根继承,但这种较彻底的实现方法耗费的时间太长,且一旦需要使用垃圾回收,则必须与框架打交道。当然就可以采用另外一种称为泛型的方法(void*)。
而新的问题又产生了,如何去存储这种指针呢?由于不是语言级机制,所以若要建立这种机制就会很容易分为主动与被动两种方式,主动既是人为去存储指针,以及对其内存块的分配。这种方式与C++、C语言本身其实是有一定程度的重复。本来C、C++提供的指针这种特性,意在时程序员能够主动、灵活操纵内存。而建立的垃圾回收机制同样是一种主动的操纵方式,其实是变相的人工操纵内存,带来的效果十分微弱。
所以我跟推荐时先被动的方式,即自动产生与回收。而由于其不是语言级机制,所以难免要涉及要产生特定的内存代理指针,以及特定的内存分配方式。
云风GC是我觉得一个很棒的垃圾回收例子。虽说是用C实现,内部有很多移位,hash函数。但重点是mark-sweep算法的确有实现出来,建议可以去观摩其相关源码。
//To be continue...