Let's start Scheme

2011-02-01

BoehmGCで気になること

BoehmGCを使っていていろいろ気になることが起きてきた。
正直起きてほしくはない、が現実を受け入れる。使い方が悪いのか?

現象としては、おそらく回収されてはいけないメモリが回収されてるっぽい。保守的なGCにもかかわらず!!
正確には静的に置いてあるハッシュテーブルの中身がある回数参照されたあと変な値になるというもの。
詳しく調べてないし、GDBで確認するのと普通の流すので結果が変わるので調べ難い(ひどい話である)ので、断言はできないが。
DLL内でGC_INIT()を呼んで、exeメインのファイルでもGC_INIT()を呼んでいるが、これがまずいのか、それともCygwinでは静的に置いた値に対して特別な処置がいるのか、どっちかは分からない。
涙が出そうになったのでデバッグを適当に切り上げてしまった。続きはまた明日。

どうでもいい話だが、どうやってポインタが指すポインタを判別してるんだろう?
例えば
typedef struct a
{
  int tag;
  void *addr;
} A;

int main()
{
  A *ap = GC_MALLOC(sizeof(A)); /* (1) */
  char *strp = GC_MALLOC(10);
  ap->tag = 1;
  ap->addr = strp; /* (2) */
  return 0;
}
プログラムに意味は無いが、こんなのがあった場合、(1)はいいだろう、スタックから辿れる。(2)はもしapがどこかで作られたものなら、strpのスタック上のアドレスは完全に消える。この場合、struct Aの中身を1byteもしくはalignのサイズ(例えば2byte)ずつ見ていき、GCが抱えるヒープ上のアドレスを保持しているかどうかというのを見るのだろうか?
こんな感じ?
void follow(void *obj, size_t size)
{
  uintptr_t addr = (uintptr_t)obj;
  int i;
  for (i = 0; i < size; i++) {
    void *p = (void*)(addr + i);
    /* p が指すアドレスの先がヒープを指しているか? */
    if (in_heap(*p)) {
      /* ヒープは割り付けたメモリのサイズを管理する */
      follow((void*)*p, get_size_from_heap_header(*p));
    }
  }
}
これなら一応アドレスを辿れそうに見える、試してないけど。

仮に、BoehmGCがこんな感じのことをしてたとして、誤回収が起きるのはどうしてだろう?もしくは、メモリを中身を書き換えてるのかも?
ソース読めば早いのだろうが、あれを読んで理解するのはかなり大変だよなぁ・・・そこまで時間をかけたくないし、なんかいい解決方法ないだろうか?

No comments:

Post a Comment