随笔 - 119  文章 - 290  trackbacks - 0

博客搬家了哦,请移步
叫我abc

常用链接

留言簿(12)

随笔分类

我的博客

搜索

  •  

积分与排名

  • 积分 - 302260
  • 排名 - 84

最新评论

阅读排行榜

stack_pack将堆栈中的内存和所分配的函数之间建立依赖关系之后,就到了对 E.pool中所有管理的内存进行标记的时候了。

 1static void
 2gc_mark(int root)
 3{
 4    if (E.pool[root].mark <  E.mark+1{
 5        struct link *children=E.pool[root].u.n.children;
 6        E.pool[root].mark=E.mark+1;
 7        if (children) {
 8            int i;
 9
10                for (i=children->number-1;i>=0;i--{
11                    gc_mark(children->children[i]);
12                }

13        }

14    }

15}
由于暂时还不想考虑weak table的内容,我暂时将这一部分的代码去掉。
来看看是如何对内存队列进行标记的。首先,形参root是依赖关系的父节点,是 E.pool数组中的索引。在gc_collect中 root = 0,表示从全局根节点开始,更准确的说从main函数对象开始,遍历整个依赖关系构成的树,对每一个节点进行标记。
第4行,是对节点是否已经被标记的判断。第6行对该节点进行标记。第10、11行则对该节点所引用的子节点重复这一标记过程。
整个依赖关系是树状的,利用先序遍历标记所有还被引用的内存节点。这就是gc_mark所作的工作。

最后,是对所有没有标记过的内存进行回收。
 1    for (i=0;i<E.size;i++{
 2        if (E.pool[i].mark < E.mark) {
 3            if (E.pool[i].mark >= 0{
 4                void *p=E.pool[i].u.n.mem;
 5                if (E.pool[i].u.n.finalizer && E.pool[i].u.c.weak!=WEAK_CONTAINER) {
 6                    E.pool[i].u.n.finalizer(p);
 7                }

 8                if ((intptr_t)p != FREED_POINTER) {
 9                    my_free(p);
10                    map_erase(i);
11                }

12                node_free(i);
13            }

14        }

15        else if (E.pool[i].mark == E.mark) {
16            void *p=E.pool[i].u.n.mem;
17            if (E.pool[i].u.n.finalizer && E.pool[i].u.c.weak!=WEAK_CONTAINER) {
18                E.pool[i].u.n.finalizer(p);
19                E.pool[i].u.n.finalizer=0;
20            }

21            my_free(p);
22            map_erase(i);
23            E.pool[i].u.c.mem=FREED_POINTER;
24        }

25    }
用for循环遍历 E.pool,所有分配的内存,因为被标记的内存的值是 E.mark + 1,所以只要 E.pool[i].mark <= E.mark的,都算是垃圾内存了,因此for循环里面的两个 if 和 else if在垃圾内存的角度上并没有差别,都是被回收的内容,但是这两个代码块多少还是有差异的,因此稍微想了一下。
首先,从之前做标记的代码看,没有被标记过的内存应该是小于 E.mark的,因此if代码块是理解上的正常流程。而else if 部分,检测内存的标记等于 E.mark,这个怎么看都是没有可能的,因为标记值是 E.mark+1,而E.mark以+2递增。这有可能是其他一些我还没看过的代码,对节点进行了标记也说不定,毕竟还有一个weak_table没有接触呢。
此外还有一个细节,else if部分,没有调用node_free(i),释放了内存,但是节点保留着,这让我更确认这是一块还没有开辟的代码区域造成的,不过,这还是等以后看到相关内容的时候,再来考证这里的内容吧。

最后,来看看gc_link中解除依赖关系的代码,现在已经对整个gc库有了整体的认识,这部分代码也就不在话下了
1    if (prev) {
2        int prev_id=map_id(prev);
3        stack_push(prev_id);
4        node_add(parent_id,prev_id | UNSET_MASK);
5    }
第3行,将被解除关系的内存id压入堆栈,看起来目的是让这块内存再稍微活长久一点,至少要活到离开当前函数后。
然后第4行,解除了之前主动添加的依赖关系,在cache_flush的时候,将会从children数组中删除prev_id。
posted on 2008-09-22 21:55 LOGOS 阅读(4804) 评论(4)  编辑 收藏 引用 所属分类: 垃圾收集

FeedBack:
# re: 垃圾收集的那点事(J) 2008-09-22 22:44 来支持
都还没去下过云风原始的代码,到是从博主这里看出一点头绪来,这么感觉出有点LUA的味道啊。对lua研究不深,随便说说,呵呵。  回复  更多评论
  
# re: 垃圾收集的那点事(J) 2008-09-23 10:32 cexer
哪里有下载的源码  回复  更多评论
  
# re: 垃圾收集的那点事(J) 2008-09-23 10:57 LOGOS
# re: 垃圾收集的那点事(J) 2008-09-23 17:40 cexer
@LOGOS
多谢了,我也研究研究。  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理