MRubyのincremental_sweep_phaseを読んでみた。
struct heap_page *page = mrb->sweeps;
でpageをスタート。
while (page && (tried_sweep < limit))
でnextのpageへループ
その中で
RVALUE *p = page->objects;
RVALUE *e = p + MRB_HEAP_PAGE_SIZE
このpとeの間でまたループ。
while (p<e)
if (is_minor_gc(mrb) && page->old) {
/* skip a slot which doesn't contain any young object */
p = e;
dead_slot = 0;
}
もしpage->oldならこのwhileの部分はスキップする(p==eでwhile終了)。
int dead_slot = 1;
このdead_slotはまだ使われているobjectがあると0となり下の
if (dead_slot && freed < MRB_HEAP_PAGE_SIZE) {
でelseへ飛ぶようになる。
if (is_dead(mrb, &p->as.basic)) {
if (p->as.basic.tt != MRB_TT_FREE) {
obj_free(mrb, &p->as.basic);
p->as.free.next = page->freelist;
page->freelist = (struct RBasic*)p;
freed++;
}
}
もし死んでいたらfreeしてそのポインタをpage->freelistにつなげる。
そのつなげ方はまずfreelistのポインタをpのnextにいれてそのあとpを
freelistに入れる。
もしpが死んでいなかったならdead_slotをゼロにしておく。
これで後にこのpageはfreeされない。
if (dead_slot && freed < MRB_HEAP_PAGE_SIZE) {
dead_slotでMRB_HEAP_PAGE_SIZE以内でfreeされていたら(ここでヒープサイズ以上にfreeされることはあるのか?)
このページをlistからはずしてfreeする。
unlink_heap_page(mrb, page);
unlink_free_heap_page(mrb, page);
mrb_free(mrb, page);
page = next;
dead_slotでなかった場合
もし最初にfreeがなかったがfreeされた場合
if (full && freed > 0)
ヒープにつなぎ直す。
link_free_heap_page(mrb, page);
次にfreelistが無くなっていたらoldをtrueにして次のsweepではスキップするようにしておく。
if (page->freelist == NULL && is_minor_gc(mrb))
page->old = TRUE;
else
page->old = FALSE;
page = page->next
次のページでまた同じことをする。