垃圾收集的那点事(H)

垃圾收集的那点事(H)

昨天已经通过gc_enterstack_push的实现,了解到用一个近似调用堆栈的东西,保存每一级调用中分配的自由内存的id。
今天看看gc_leave。gc_leave有一个可变参数列表,这些参数的用途是,将本函数分配的自由内存的声明周期再保留更长一点的时间。
看看实现就知道了:

 1 void
 2 gc_leave( void   * p,)
 3 {
 4    void **head;
 5    if (E.stack.current >= E.stack.bottom) {
 6        E.stack.top = E.stack.current;
 7        E.stack.current -= E.stack.data[E.stack.current].number;
 8    }

 9    else {
10        int parent,child;
11        --E.stack.bottom;
12        parent=E.stack.data[E.stack.bottom-1].stack;
13        child=E.stack.data[E.stack.bottom].stack;
14        node_add(parent, child | UNSET_MASK);
15        node_free(child);
16        E.stack.current=E.stack.bottom-1;
17        E.stack.top = E.stack.current + 1;
18    }

19
20    head=&p;
21
22    while (*head) {
23        stack_push(map_id(*head));
24        ++head;
25    }

26}

我们知道,调用gc_leave,也就意味着要离开当前的函数回到父函数上了,那么堆栈也要退回到父函数调用gc_enter后的情形。
首先看if部分,因为在 E.stack.current的位置上保存的是父函数中分配的自由内存的数量,所以第6行让top指向这里,第7行用current对这个数量做一个减法,就变成了父函数堆栈的情形了。

不过9行else部分比较令人困惑。仅仅在第一次调用gc_enter之前,current会小于bottom,此时current=0,bottom=1。那么接下来的第11行执行后bottom=0,第12行看起来就会访问索引为-1处的数据。我还没有跑过这个库,也没有在源码中搜索出 E.stack.bottom比较特殊的赋值操作,所以不太确定到底是怎么回事。所以,这个先暂时放下,等以后看到其他内容,或者跑一下这个库的时候,再搞清楚这段代码的意义。

最后是一个while循环,处理可变参数列表,这些参数是需要延长生命的自由内存指针。怎么做呢?因为现在已经回到了父函数的gc堆栈上,所以就把这些需要延长生命的自由内存压入父函数的gc堆栈即可,见23行。
不过这也意味着,他们的生命最少只延长到父函数也退出而已。

OK,看完了分配出来的内存的两种管理方式,明天终于可以看看如何进行内存回收了。

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