2013/07/27
保守的gcとスタック
Conservative GC 使ってる時に、スタックにポインタぽいものが残ると、もう使ってなくてもメモリが解放されないみたいな話があって、コンパイラで関数から出る時にポインタを持ちうるメモリをクリアすると良いかなぁと作った clang plugin 。
GaucheでもVM stackにポインタが残る可能性はあって前から気にはなっていた。 ただ、それが問題となる状況を実際に起こすのはかなり難しい。Gaucheの場合、 スタックがある程度以上深くなるとヒープにごそっと移されて各フレームが 回収対象になるので、「スタック溢れが起きない程度で、かつ大部分の関数呼び出しよりも 深い呼び出しの中で大きなデータを指すポインタを作る」って条件が結構厳しい。
ただ、可能性があるのは確かで、思わぬ時に噛みつかれる恐れがあるのは落ち着かない。
リターンするたびに使ったスタック領域をクリアする、というのはオーバヘッドがあるし、 ほとんどの場合その領域は直ちに再利用されるので、無駄が多い。
(一応、昔「VM stackの有効部分だけをmarkする」というコードを入れてみたことはあった のだけど、特に性能に変化は見られなかったので無効にしてある。)
最近考えているのは、 ほとんど起きない事象なら、「ある程度の時間間隔で未使用スタック領域をクリアする (例えばGCのsweep phase 10回につき1回とか)」でもいいんじゃないか、という アイディアだ。 いずれクリアされるものなら、いつまでも回収されないという事態は防げる。
その実装自体は難しくないのだけれど、Gaucheの場合VMがスレッド毎にあり、 プロセス中の全てのVMを知るインタフェースが無いのがちと問題。 GCが走ったスレッドに関してだけクリアすると、 止まったままのスレッドのVMがゴミを掴んでいるケースに対応できない。
Boehm GCの方で全スレッドのリストは把握してるので、全VMを辿ることも 強引にできなくはないんだが…
shinh (2013/07/28 12:25:05):
shiro (2013/07/28 19:50:32):