GC mark が超遅い

初期化コードを Gauche で生成するようにしたので、初期化順序の問題に頭を悩ませなくて良くなったのも束の間。
GC を含めてビルド → 実行すると異様に重い。

  • 数十秒返ってこない
  • double free で落ちる

double free の問題は sweep をコメントアウトして後で考えるとして gc_mark が重い気がするのでプロファイラで計測。

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls   s/call   s/call  name    
 75.10     13.27    13.27    33746     0.00     0.00  gc_mark_heap(GCNode*)
 24.56     17.61     4.34        1     4.34    17.66  gc_mark()
  0.28     17.66     0.05        1     0.05     0.05  gc_mark_registers()
  0.06     17.67     0.01    20421     0.00     0.00  util::String::set(char const*)
  0.00     17.67     0.00    51083     0.00     0.00  util::String::operator[](unsigned int) const
  0.00     17.67     0.00    45658     0.00     0.00  util::String::size() const
  0.00     17.67     0.00    33749     0.00     0.00  gc_node_initialize(GCNode*)

これはひどいな。
というわけで調べよう。
gc_heap_min = 8092007 gc_heap_max = 874d199 約 7MB を走査するのに数秒かかっている。
いろいろ調べたけど

  • heap の中を 1byte ずつずらして 4byte 単位でチェック
  • 上記チェックが割り当てブロックの数 30,000回だけ呼ばれる

と、かけ算的に死ぬほど呼ばれているのが問題だ。


今採っている方法は根本的にダメだってことだな。
これは作ってみないと分からなかった。勉強になる。
頭の中で考えていた方法が、こんなに遅いとは想像してなかったよ。ワクワクしてきた。
というわけで論文読んできます。