昨天看完了
cache_flush,有关
gc_malloc的内容,就到此为止了。接下来,就是补看这一路上暂时略过的一些函数,顺便引出对malloc出来但是没有建立依赖关系的内存是如何管理的。
其实这一路过来,就忽略了两个函数:
map_id和
stack_push。有关map_id的作用已经说过,仍打算继续忽略下去。至于stack_push分别出现在了
gc_malloc和
gc_link中,在gc_link中作为解除内存依赖关系的一个步骤,可以以后再看,而在gc_malloc中,是在没有提供parent参数的时候的一个执行分支,也就是新分配的内存没有建立依赖关系而进行的另外一种管理,这种管理使得内存可以被
gc_collect回收。
如果要看stack_push,就必须先看
gc_enter和
gc_leave,根据提供的说明,这两个函数对必须在应用程序的每个函数的开始和结束调用,也可以只是简单的放置在main loop中,而不必填充到每一个函数里。光介绍概念还是太抽象,直接看代码来得实惠。
1void
2gc_enter()
3{
4 stack_expand();
5 E.stack.data[E.stack.top].number=E.stack.top-E.stack.current;
6 E.stack.current=E.stack.top++;
7}
忘了说,这一块内容,其本质都是对stack进行操作,所以第4行,首先拓展stack的尺寸。stack_expand里面包含一个拓展策略,因为我看不懂,就不介绍了,总之,其结果就是保证了stack总是有足够的空间而很少越界。
第5、6行,看起来还是要配上云风画的图可能更容易理解
/* stack data
+----------+
0 | level 0 | ----> level 0 / root ( node pack )
1 | level 1 | --+-> level 1 ( 1 node ref + node pack )
2 | node ref | <-bottom --+
3 | 2 (lv.2) |
4 | node ref | --+-> level 2 ( 3 node ref )
5 | node ref | |
6 | node ref | --+
7 | 4 (lv.3) | <-current
8 | node ref | --+-> level 3 ( 2 node ref )
9 | node ref | --+
10| nil | <-top
11| nil |
+----------+
*/
在top和current之间,保存的是在父函数中分配而没有建立依赖关系的内存的id。所以第5行,就是把父函数中分配的自由内存的数量压入堆栈。第6行则让current指向这个位置。
结论也就是,相对当前的函数而言:
1.current指向的数据是爷爷函数中分配的自由内存的数量
2.top和current之间保存的是父函数中分配的自由内存的id
通过调用gc_enter,堆栈调整为:current指向的数据保存着父函数中分配的自由内存的数量,而现在top和current之间空无一物,用于存储当前函数将要分配的自由内存id。
下面看看stack_push的代码
1static void
2stack_push(int handle)
3{
4 stack_expand();
5 E.stack.data[E.stack.top++].handle=handle;
6}
参数handle就是新分配的内存的id。代码就2行,首先是拓展stack,然后就是把内存id压入堆栈,放在top和current之间。这也就解释了上面的那个堆栈的布局结构如何而来。
最后,贴一下stack的定义。因为前两个函数都有些简单,以至于忘记看数据结构的定义了
union stack_node {
int stack;
int number;
int handle;
};
struct stack {
union stack_node *data;
int top;
int bottom;
int current;
};
stack即堆栈,内部用一个数组实现,即成员变量data。数组元素为stack_node。
由stack_node的定义可知,堆栈的一个元素可能表示3种用途:
1.stack,不知道
2.number,存储父函数,爷爷函数等等的函数中分配自由内存的数量
3.handle,存储某个函数分配出来的自由内存的id
that is today
posted on 2008-09-17 21:02
LOGOS 阅读(1540)
评论(0) 编辑 收藏 引用