[TOC]
已经有很多人写了gc源码分析的文章了,自己为啥还要继续写呢?最主要的原因有两个:
mark & sweep算法,维基上的词条叫Tracing garbage collection[1].
根据名字也可以知道,最主要包括两个阶段:mark阶段和sweep阶段。
这个阶段叫做扫描阶段。简单来讲,就是对于现在lua用到的所有对象进行扫描一次。如果某个对象当前跟别的对象有引用关系,那么说明他还在用;如果某个对象跟其他任何对象都没有引用关系了,说明这个对象已经没有用了。这个阶段做完,就可以知道哪些对象还有用,哪些对象不再使用了,下面就交给下一个阶段,sweep阶段。
注意:这里说到的引用关系,很多文章没有解释清楚,只是大概说明了一下。这里先简单介绍一下,lua的扫描阶段虽然最终是对所有对象扫描了一遍,但是并不是遍历gc链表(这个链表放了lua所有的可回收的对象),而是先把最顶层的几个节点放在一个池子(另外一个链表)里面,然后递归深入这个对象,新遍历到的对象说明有引用关系。把新遍历的对象放入池子,继续递归深入遍历,这样就等于把所有有引用关系的对象遍历了一遍,那么没有遍历过的对象就自然是跟其他任何对象都没有引用关系的了。
这个阶段做的事情其实很少,关键步骤在前一个阶段做完了。这个阶段根据前一个扫描阶段得到的结果,遍历一遍所有对象。如果这个对象已经标记为不再使用了,就会被清理掉,释放掉所在的内存;如果这个对象还在使用,那么就处理一下状态,等待下一次gc在处理。
这里说的很简单,至于扫描阶段做了什么,怎么个标记法;以及处理阶段又具体做了什么,被引用的对象,清理状态又干了什么,这些细节等待后面深入lua源码的时候再一一分析。
如果mark阶段一次性把所有节点都扫描,再一次性清理完,那么这两个步骤就都很简单了。但是,这样就有效率问题,一次性要把所有对象处理一遍,在大工程里面就绝对是一个瓶颈。所以,lua5.0以后就把gc改成了增量式的gc,主要是把标记扩展成了三种颜色,下面详细介绍一下。
三种颜色会让lua的gc,主要是扫描和清理阶段不再简单粗暴,而是一次性处理一部分,可以随时中断,下次再进来处理。三种颜色:包括白, 灰和黑。[2]
注意白色是有两种,后面再详细介绍。
这个地方提个小问题思考一下:某个对象递归深入扫描完之后,说明他肯定是黑色的,是不是就可以不管他了呢?
下面给出一个数据流的图[2],详细的内容后面的章节再继续阐述。
[1] Tracing garbage collection
[2] ch08-GC