GC本の疑問点

2010-04-03

 マークスイープGCを再度実装しながらGC本を参照しててマークスイープGCの章を読んでると「やっぱこれダメなんじゃ?」と思ったんだけど、「よく考えてみると大丈夫なのか」と思ったんだけど、「でもやっぱこれだとダメなんじゃ?」と思った。

最初にダメなんじゃないかと思ったのは、2.1マークスイープGC/2.1.3 スイープフェーズのリスト4 sweep_phase()でヒープを順になめてくけど、アプリの実行が進んでフリーリストに小さいサイズしかなくて使われてない領域がある状態でGCが起動した場合に、その使われてない領域もスキャンしちゃうからまずいんじゃないか?と思った。

でも使われてない領域はマークされてないはずだから、それらのチャンクにも.sizeがちゃんと入ってれば別にスキャンしてしまってもいいのか、と一旦は納得した。 見なくてもいい空き領域をスキャンするから無駄なのと、オブジェクトのデストラクタを呼び出す必要がなければ。

でも回収するときにフリーリスト$free_listにつないでしまってるので、やっぱダメなんじゃないかと思った。 空の領域は$free_listにつながれた状態でGCが起動するわけだから、さらにフリーリストにつないでしまうとリストが循環してしまうのではないかと思う。

解決策としては、スイープフェーズの頭でフリーリストを空にしてやればいいと思う:

  1: sweep_phase() {
1.5: $free_list = NULL // <- 挿入
2: sweeping = $heap_start
...

ヒープ領域は全体なめるはずなのですべてのチャンクは再度スキャンされ登録されるはず。 Coalescingをするリスト6のsweep_phase()も同様。

あと、いつGCが起動するのかという疑問が。 2.1.4アロケーションのリスト5 new_obj()関数ではpickup_chunk()の呼び出しでNULLが返ってきたらallocation_fail()してしまってる。 pickup_chunk()は名前からすればGCの起動まではしないだろうから、new_obj()からGCを起動しないと自動的にGCされないことになってしまうんじゃないかと思う:

1: new_obj(size){
2: chunk = pickup_chunk(size, $free_list)
3: if(chunk == NULL)
4: mark_sweep()
5: chunk = pickup_chunk(size, $free_list)
6: if(chunk == NULL)
7: allocation_fail()
8: return chunk
9: }

頭で考えただけで実装はしてないので、確証はない。