ガーベジコレクション
最近の言語、特にスクリプト言語において、ガーベジコレクションを採用しないのはありえません。
当然Xtalもガーベジコレクションを持っています。
Xtalは紆余曲折の結果、一番原始的なgcのアルゴリズム、参照カウントgcを採用することにしました。
途中まではMark and Sweep、世代別、インクリメンタルgcで動いていたのですが、C++で拡張を書く時に次のような問題が出ることに気づきました。
- Cスタックやレジスタから指されているオブジェクトの自動判定は信頼性が薄い。最適化で参照が消えてしまう可能性がある。
- 世代別、インクリメンタルを実装するにはwirte barrierが必須だが、write barrierは書くのが面倒で書き忘れやすい。
上から発生するバグはその箇所の発見がとても困難です。
バグを起こさないよう、色々なルールを覚えなければならなくなるでしょう。
C++との連携を最優先事項の一つとして考えている以上、これは避けなければなりません。
色々考えた結果、C++と一番相性がいいのはやはり参照カウントgcだろう、ということに落ち着きました。
参照カウントを採用してはいるのですが、一般に想像される参照カウントと違う挙動があります。
- 参照カウンタが0になったからといって、即座に解放はされない
gc関数を呼び出したときに初めて参照カウンタが0のオブジェクトを解放します。
これは参照カウントのオーバーヘッドがバカにならない部分では参照カウンティングを止めているためです。
例えば仮想マシンの内部の計算では参照カウンティングをしていません。gcが走る直前に仮想マシン内部で保持しているオブジェクトの参照カウントを上げ、gcが走り終わった直後に参照カウントを下げることで整合性を保っています。
- 循環参照も解放できる
循環参照を解放できないようでは安心して使うことができません。循環していないかビクビクしてプログラミングするのはイヤでしょう。気をつけていたとしてもうっかりなってしまうことはありえます。そのため内部に循環参照を検出できるような仕組みが組み込まれています。