gcのモデル
作ってみました。勉強のため。マーク&スイープgcというらしい。
- 再利用可能なオブジェクトのリストがあり、
- 新しくオブジェクトをつくるときはそこからとる。
- そのときにリストが空ならgcを起動
- ルートオブジェクトから辿れるオブジェクトすべてにマークを入れる
- オブジェクトを走査してマークのついていないものを再利用可能リストに連結する
わかりやすい。利点は必要な時にだけgcが動くのでgcが動いていないときに高速に動作できる事で、欠点は一度起動するとオブジェクトすべてを走査するので線形のオーダーでコストがかかる事。だそう。今回のプログラムでは、ルートからすべてのオブジェクトに到達可能なときはexit()しています。より洗練された実装だとオブジェクト構造体の配列をreallocかけて増やすとかするようです。
#include<stdio.h> #include<stdlib.h> // exit #define SIZE 10 typedef struct Object { int mark; struct Object *next; } object; object obj_array[SIZE]; object NIL; object *free_list; object *root; void init(void); void gc(void); object* get_new(void); void init(void) { int i; // init important objects NIL.mark = 1; NIL.next = &NIL; free_list = &NIL; root = &NIL; for (i = 0; i < SIZE - 1; i++){ obj_array[i].mark = 0; obj_array[i].next = &obj_array[i+1]; } obj_array[i].mark = 0; obj_array[i].next = &NIL; free_list = obj_array; } void gc(void) { int i; object *tmp; printf("launch gc..."); // marking objects can be traced from root object for (tmp = root; tmp != &NIL; tmp = tmp->next) tmp->mark = 1; // if not marked, then link to free list. for (i = 0; i < SIZE; i++) if (obj_array[i].mark == 0){ obj_array[i].next = free_list; free_list = &obj_array[i]; } printf("done\n"); } object* get_new() { object *tmp; if (free_list == &NIL){ gc(); // if free list is NIL, then execute gc if (free_list == &NIL){ // still NIL printf("memory starvation\n"); exit(0); } } tmp = free_list; free_list = free_list->next; // init tmp->mark = 0; tmp->next = &NIL; return tmp; } int main(void) { int i; object *x, *y; init(); x = get_new(); y = get_new(); x->next = y; root = x; // current status: // root -> x -> y -> NIL for (i = 0; i < 10; i++) // force gc x = get_new(); return 0; }