# 2019q1W7下: 陳冠廷
### 測驗 `1`
程式碼中利用 `__gc_object.ptr_map[i]` 加速 linked list 存取
每當呼叫 `gc_alloc` 時,會在 hashmap 中對應的 linked list 插入一個`gc_list_t` 用於保存 malloc 的地址以及大小和一個 marked 的 flag,在稍後的 GC 流程中會使用到(注意在建立時不會設定 marked)
除此以外也會將 `__gc_object.ptr_num` 的值加 1
:::warning
搭配解釋 `HASH` 巨集的用法
:notes: jserv
:::
在 `__gc_object.ptr_num >= __gc_object.limit` 的情況下呼叫 `gc_alloc()` 就會觸發 `gc_run()` 執行 garbege collection,做法是從目前的 stack 頂端也就是下方程式碼中的 `&tmp` 開始,掃到最一開始在 main 中設定的 `__gc_object.stack_start`
```cpp
void gc_mark_stack(void)
{
uint8_t tmp;
gc_mark(__gc_object.stack_start, &tmp);
...
}
```
```cpp
int main(int argc, char *argv[])
{
gc_init(&argc, 1);
...
}
```
將存在這個區段中的任意值取出來作為指標,接著到 hashmap 中查詢該指標是否是使用者透過 `gc_alloc()` 所配置的記憶體,若是則標註 `idx->data.marked` 並以相同方式繼續在該記憶體區段中 dfs 搜尋,若非就不做任何改變
:::warning
其實只是從`gc_mark_stack()`的 stack frame 隨便挑一個位置開始算到 `main()` 結束,所以實際上若是 stack 上有殘留沒被清除或覆蓋掉的`gc_alloc()`指標就會多算
:::
```cpp
void gc_mark(uint8_t *start, uint8_t *end)
{
if (start > end)
swap_ptr(&start, &end);
while (start < end) {
gc_list_t *idx = gc_ptr_index((uintptr_t)(*((void **) start)));
if (idx && idx->data.marked != true) {
idx->data.marked = true;
gc_mark((uint8_t *) (idx->data.start),
(uint8_t *) (idx->data.start + idx->data.size));
}
start++;
}
}
```
接著 `gc_sweep()` 會遍歷 `__gc_object.ptr_map` 將沒有被標記 (marked) 的指標 free 掉,並刪除 list 中該節點,要注意的是此時若是遇到有標記的指標會將該標記清除,至此完成一次的 GC
```cpp
void gc_sweep(void)
{
for (int i = 0; ++i < PTR_MAP_SIZE;) {
gc_list_t *e = __gc_object.ptr_map[i];
int k = 0;
while (e) {
if (!e->data.marked) {
gc_mfree(e);
e = e->next;
gc_list_del(&__gc_object.ptr_map[i], k);
} else {
e->data.marked = false;
e = e->next;
}
k++;
}
}
}
```