On The Road
(cond ((less 'code) (less 'bug)))
C++博客
首页
新随笔
联系
聚合
管理
随笔 - 119 文章 - 290 trackbacks - 0
博客搬家了哦,请移步
叫我abc
常用链接
我的随笔
我的评论
我参与的随笔
留言簿
(12)
给我留言
查看公开留言
查看私人留言
随笔分类
《GAME PROGRAMMING GEMS6》读书笔记(4)
《UNIX编程艺术》读书笔记(4)
month-flow(5)
mysql入门(3)
垃圾收集(4)
我的博客
叫我abc
博客搬家啦
搜索
积分与排名
积分 - 301916
排名 - 84
最新评论
1. re: C++ std::fstream open mode
i'am got
--hdj
2. re: cppcheck的使用
你好,你会使用cppcheck吗?@robert
--wqq
3. re: 垃圾收集的那点事(H)
非常感谢
--7Qing_
4. re: 高效调用lua函数
为什么提示没有findLuaItem这个函数?
--sdfasf
5. re: android ndk调试知识[未登录]
博主你好,请问如果没有.so的源代码,应该如何进行arm的汇编级调试呢?
--dennis
阅读排行榜
1. cppcheck的使用(16931)
2. 十步精通新语言(10624)
3. 内存池实现(9864)
4. 高效调用lua函数(9201)
5. 在lua脚本中使用unicode(8157)
垃圾收集的那点事(J)
继
stack_pack
将堆栈中的内存和所分配的函数之间建立依赖关系之后,就到了对 E.pool中所有管理的内存进行标记的时候了。
1
static
void
2
gc_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
阅读(4799)
评论(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
@cexer
http://manualgc.googlecode.com/svn/trunk
回复
更多评论
#
re: 垃圾收集的那点事(J)
2008-09-23 17:40
cexer
@LOGOS
多谢了,我也研究研究。
回复
更多评论
刷新评论列表
只有注册用户
登录
后才能发表评论。
【推荐】100%开源!大型工业跨平台软件C++源码提供,建模,组态!
相关文章:
gc库概念简化版
垃圾收集的那点事(K)
垃圾收集的那点事(J)
垃圾收集的那点事(A)
网站导航:
博客园
IT新闻
BlogJava
知识库
博问
管理