Ruby的GC机制源码分析(4)

标记

正如说过的那样,ruby 的GC是标记和清除型。具体来说,标记就是设置FL_MARK 标志。搜索已用的VALUE ,设置FL_MARK ,全部检查过之后,再来看对象堆,释放那些没有设置FL_MARK 的对象。

rb_gc_mark()

rb_gc_mark() 是一个递归标记对象的函数。

rb_gc_mark()

Ruby的GC机制源码分析(4)

首先,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()

Ruby的GC机制源码分析(4)

Ruby的GC机制源码分析(4)

rb_gc_mark() 是递归的调用,确认这点就可以了。省略的部分分别是NODET_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 就无需标记了。