# 2019q1 Homework6 (gc) contributed by < `jeffcarl67` > ## 環境 * 4.19.36-1-MANJARO * gcc (GCC) 8.3.0 ## ogc 原理 ### init , destroy orc 的運作從函式 `gc_init` 開始,到函式 `gc_destroy` 被呼叫時結束,整個 garbage collector 使用一個全局變數 `__gc_object` 記錄狀態,`__gc_object` 的類型定義於 `gc_internal.h` 中,如下: ```c= struct __gc { void *stack_start; gc_list_t *ptr_map[PTR_MAP_SIZE]; size_t ptr_num; size_t limit; size_t ref_count; uintptr_t min, max; gc_list_t *globals; }; ``` 在這個結構中,變數 `stack_start` 用於記錄整個程式 stack 的起始位置,`ptr_map` 為一個用於記錄以分配記憶體的 hash table,`ptr_num` 記錄以分配記憶體塊的數量,`limit` 用於限制 garbage collector 中容許存在的以分配記憶體塊的上限,當分配的記憶體塊上限大於此值時,garbage collector 就會開始 garbage collection,`ref_count` 記錄函式 `gc_init` 被呼叫的次數,以決定當函式 `gc_destroy` 呼叫時採取的行為,`min`,`max` 記錄 heap 的上下界限,可用來判斷要操做的記憶體是否合法,而變數 `globals` 的用途暫時還不清楚 再看到函式 `gc_init` 與 `gc_destroy` : ```c= void gc_init(void *ptr, size_t limit) { if (__gc_object.ref_count) { __gc_object.ref_count++; return; } __gc_object = (gc_t){.stack_start = ptr, .ptr_map = {NULL}, .ptr_num = 0, .ref_count = 1, .limit = limit, .min = UINTPTR_MAX, .max = 0, .globals = NULL}; } ``` ```c= void gc_destroy(void) { __gc_object.ref_count--; if (__gc_object.ref_count <= 0) { __gc_object.ref_count = 0; for (int i = -1; ++i < PTR_MAP_SIZE;) { gc_list_t *m = __gc_object.ptr_map[i]; while (m) { gc_list_t *tmp = m; free((void *) (m->data.start)); m = m->next; free(tmp); } __gc_object.ptr_map[i] = 0; } } } ``` 可以發現都只是在操作 `__gc_object` 中記錄的資料 ### mark , sweep ogc 採用 [Mark and Sweep](https://www.youtube.com/watch?v=2XKifr16o7Y),在每次執行函式 `gc_run` 時會先呼叫函式 `gc_mark_stack` 檢查 stack 中是否存在之前分配的記憶體塊的位址,若找到就代表該記憶體塊仍在使用中因此其標記為 `true`,之後呼叫函式 `gc_sweep` 將未被標記為 `true` 的記憶體塊釋放,此機制的關鍵函式在 `gc_mark` 與 `gc_sweep`,其實作如下: ```c= 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++; } } ``` ```c= 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++; } } } ```