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回だけ呼ばれる
と、かけ算的に死ぬほど呼ばれているのが問題だ。
今採っている方法は根本的にダメだってことだな。
これは作ってみないと分からなかった。勉強になる。
頭の中で考えていた方法が、こんなに遅いとは想像してなかったよ。ワクワクしてきた。
というわけで論文読んできます。