http://aiku.me/bar/10113853
标记
正如说过的那样,ruby
的GC是标记和清除型。具体来说,标记就是设置FL_MARK
标志。搜索已用的VALUE
,设置FL_MARK
,全部检查过之后,再来看对象堆,释放那些没有设置FL_MARK
的对象。
rb_gc_mark()
rb_gc_mark()
是一个递归标记对象的函数。
▼ rb_gc_mark()
首先,RANY()
定义如下。没什么特别的。
▼ RANY()
295 #define RANY(o) ((RVALUE*)(o)) (gc.c)
首先,检查那些不是指针的东西和已经释放的对象,以及对已标记对象的递归检查。
obj->as.basic.flags |= FL_MARK;
这样obj
(也就是函数的参数ptr
)就被标记了。之后,顺着从obj
出来的引用进行标记。rb_gc_mark_children()
就是这样。
其它的,从CHECK_STACK()
开始,主要是为了写了些各种各样防止栈溢出的代码。 rb_gc_mark()
使用递归调用对对象进行标记,如果出现大的对象簇,机器栈的长度可能就会不足。在栈要溢出的时候,停止递归,将对象都放到全局列表中,再重新开始标记。因为这部分代码不是主线,省略过去。
rb_gc_mark_children()
下面是rb_gc_mark_children()
,它只是将内部类型罗列出来,然后标记,冗长无趣。这里省略了一些纯粹是枚举的部分。
▼ rb_gc_mark_children()
rb_gc_mark()
是递归的调用,确认这点就可以了。省略的部分分别是NODE
和T_xxxx
的枚举。 NODE
的事会在第二部分介绍。
T_DATA
(用于扩展程序库的结构体)标记的部分需要确认一下。这段代码是从第二个switch
语句中提取出来的。
▼ rb_gc_mark_children()
-T_DATA
789 case T_DATA: 790 if (obj->as.data.dmark) (*obj->as.data.dmark)(DATA_PTR(obj)); 791 break; (gc.c)
这里用的不是rb_gc_mark()
,也不是与之类似的函数,而是来自用户的函数dmark
。其中当然应该用到rb_gc_mark()
,不过,也可能不用。比如,一个极端的情况,用户定义的对象中不包含VALUE
就无需标记了。