GCとPCLの和解
2011.12.23


はじめに


toy-lang にコルーチンを実装するにあたって、BoehmGC と PCL(Portable Coroutine Library) の間で色々不都合があったのでこれに対応を行ったのでその際の方法をメモとして公開します。

現在の開発中の版ではこれらのライブラリを組み合わせた際の問題はわかっており、すでに解決していますが、解決に至る中でわかったことやプログラミング上のテクニックについて参考になればと思いメモを公開します。

BoehmGCの動作について


toy-langを実装するにあたっては、できる限り汎用のライブラリを使用して実装することにしています。
toy-langにおいては、GC(ガベージコレクション)はBoehmGCを、コルーチンの実装には PCL を使用しています。

2年ほど前、コルーチンを実装していてどうしてもうまく動かなくて悩んでいました。

まず、GCの動作について非常に簡単ですが説明したいと思います。(Fig.1)



この構成の場合、メモリが足りなくなりGCが発動すると、「Fig.2GCの行われ方」のように、

  • ①ヒープ領域のGC
  • ②スタック領域のGC

が実行され、ごみ(どこからも参照されない)と判断されたメモリ領域の回収プロセスが実行されます。
特に②のスタック領域のGCでは、スタックのトップ(現在のスタックポインタ)からボトムに向かってGCが実行されます。



問題発生


上に書いたとおり、当初は各コルーチンのスタック領域はヒープ領域に確保していました。
そして、このようにすると、GCのタイミングでプロセスが確実に落ちます。
これでしばらくの間悩んでいました。2008年の冬から2009年の春ころまでです。
この間 BoehmGC のソースを眺めたり google を検索したりと原因を突き止めようとしていました。

原因


最終的にたどりついた本現象の原因は「Fig.3問題発生」のようなことではないかと推測するに至りました。



コルーチンが起動されると、それまでのスタックからコルーチンのスタックに切り替わります。
この時点でGCが発動されると、コルーチンのスタックトップから、もともとのマシンスタックのボトムに向かってGCが行われます。
そうすると、コルーチンのスタックはヒープ領域にとられているため、GCの途中でプロセスがアクセスできない領域にアクセスすることになります。
これがプロセスが落ちる原因ということであると推測しました。2009年の春頃です。

その後しばらくプログラミングから遠ざかるわけですが。

対策


で、今年よりまたプログラミングを再開し、上記問題に対応するようなコードを書きました。
それが「Fig.4解決方法」に示す内容です。



つまり、GCがスタックのトップからボトムまでをスキャンするのであれば、これを妨げるものを排除するため、コルーチンのスタック領域をすべてマシンスタックの上に配置することにしました。

実際には、プロセスが利用できるスタック領域のリソースは有限であるため、これをプログラムで知るための仕組みも作りました。

こうすることで、確かにコルーチンコールからGCが発動されても落ちることはなくなりました。推測は正しかったことになります。

あと、各コルーチンが他のコルーチンのスタックを壊さないよう、スタックの上部 4Kにバリア領域を設定しています。ここに書き込むとやはり落ちますので、今後はこのハンドルを実装しようとしています。




toy-langにコルーチンを実装しようと思い立ってからすでに三年が過ぎましたが、ようやく解決の出口がみつかりました。
次のバージョンではコルーチンをサポートしたものとなると思います。

































#eof
最終更新:2012年03月02日 10:30