垃圾收集的那点事(B)

垃圾收集的那点事(B)
继上一篇,现在可以来看看gc_malloc的源码了,初窥究竟。
 1 void *
 2 gc_malloc(size_t sz, void   * parent, void  ( * finalizer)( void   * ))
 3 {
 4    void *ret=my_malloc(sz);
 5    int id=map_id(ret);
 6    E.pool[id].u.n.finalizer=finalizer;
 7    if (parent) {
 8        gc_link(parent,0,ret);
 9    }

10    else {
11        stack_push(id);
12    }

13    return ret;
14}

首先,第4行分配了指定大小的内存。
然后是第5行map_id(ret),这是什么呢?先不深究其实现,我简单的说说他所做的工作:
因为这是一个gc库,所以本质工作就是管理内存,因此将分配出来的新内存记录到一个容器中以便于以后的管理。yfgc管理采用的容器是一个数组。分配新内存后,在数组容器中找到一个空闲的位置,将内存指针记录到该位置上。
不过光做这个还是不够的,以后要是再遇上这块内存,怎么知道它被记录在数组容器的哪个位置上呢?虽然遍历查找也可以,不过我想应该没人会那么做吧。源码采用了hash_map,将这块内存的指针map到数组的索引上。
综上,map_id(ret)大体这么做了
pool[id].mem  =  ret;
map[ ret ] 
=  id;
不过由于这个gc库是用C写的,没有STL,里面的代码就不可能那么简单啦。

总而言之,id就是内存在容器中的索引啦。从第6行可以看出,E.pool就是这个管理容器了。这句用来设置内存的析构回调函数。

E.pool是一个node结构数组,现在来看看node的定义,简单起见,我暂时去掉了不相关的东西:
1 struct  node  {
2    union {
3        struct {
4            void * mem;
5            struct link *children;
6            void (*finalizer)(void *);
7        }
 n;
8    }
 u;
9}
;
mem和finalizer很眼熟对吧,因为刚刚才看过。children可以先不管,不过从名称看来,是管理父子关系,更准确的说是依赖关系的东东了。

OK,现在来看看7、8、9行,出现了 gc_link,我记得这是一个public接口,用来管理两块内存之间的依赖关系的。现在,因为传入了parent实参,要在新分配的内存和parent之间建立依赖关系,所以调用了gc_link。

我想else部分可以先不管,只要记住出现了stack_push即可。现在非常好奇,gc_link是如何建立这一依赖关系的,采用了何种数据结构,所以接下来就要去看看gc_link的实现了。

你可能感兴趣的:(垃圾收集的那点事(B))