ライトバリアの改善策

RGenGCもmrubyも世代別GCなのでライトバリアがある。
どっちもたとえば配列aに新オブジェクトbをpushした場合に、配列aを記録しておいて後で探索するという動作をする。なぜbじゃなくaなのかと言うと、bは配列に突っ込んですぐ取り出して捨てる可能性があり(特にスタックやキューといった使い方の場合だ)、bを記録しておくとそういうオブジェクトがすべてマークされて長寿命化してしまうからだ。aを記録しておけばマイナーGCが動作した瞬間に参照しているものだけが長寿命化される。bじゃなくてaであることの問題点は、配列aに大量のオブジェクト、しかも長寿命オブジェクトが格納されていた場合に、無駄に探索する時間がかかるところだ。
RGenGCでは配列もしくはハッシュの場合に格納されているオブジェクトが多いと、bのほうを記録しておくコードが入っている。これは無限に格納されていた場合に無限に止まるということの対策ではなく(その場合どうせマークで無限に止まる)、無駄に長時間停止することの対策、つまり効率のためだろう。効率のためであれば閾値が2 << 16という値になっていることの根拠が無く、ここはたぶん今後詰められて行くんじゃないかと思う。

さて、ライトバリアでの探索は上記のように無駄が多くなってしまうことがあり、これを対策する作戦を考えてみたのでメモである。mrubyを例にする。
mrubyオブジェクトはインスタンス変数をiv_tblという情報で保持する。これをたとえばTT_IVTBLというオブジェクトを作って、それのポインタを保持するように変更する。このオブジェクトはiv_tblのみを保持する。
この状態だと、インスタンス変数を書き換えた場合に発生するライトバリアはTT_IVTBLのオブジェクトが記録されるので、iv_tbl以外の情報は探索されない。iv_tbl以外の情報を書き換えた場合はiv_tblは記録されないし黒になったままなので探索されない。ライトバリア時の探索を減らすことができる。
もちろん、インスタンス変数のアクセスに時間がかかるようになるしオブジェクトの数も増えるので一概に良いとは言えない。むしろ現実的ではない。

オブジェクトが保持する情報を可能な限りオブジェクト化して細分化すると、ライトバリアの負荷を極限まで下げることができる。究極的にはインスタンス変数1個に対してブリッジオブジェクトTT_BRIDGEを割り当てるようにする。これは他のオブジェクトへの参照を1個だけ持つオブジェクトである。するとライトバリアはTT_BRIDGEオブジェクトに発生するので、ライトバリアされたオブジェクトの探索は必ず1つに限定される。配列のデータも中にはすべてTT_BRIDGEを入れてそこから参照するようにすれば配列内のデータがいくつあろうが探索は1個となる。

まあ、実装してみようとすら思わないひどいアイデアではあるが、mrubyの改善という話ではなく、こういうネタをいつかどこかで別の何かに適用できるかもしれない、ということで、そのときのためにここに書き捨てておくのである。