昨天已經通過gc_enter和stack_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
}
void2
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,看完了分配出來的內存的兩種管理方式,明天終于可以看看如何進行內存回收了。


