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
次のページでまた同じことをする。