♻️

RustでもGCを使いたい

2024/03/11に公開

はじめに

Rustには優れた所有権システムおよびRc<T>/Arc<T>があるので通常はGCを必要としないのですが、どうしても循環参照(それもrc::Weak<T>では解決できないタイプの)が必要となるケースというのが多数存在します。具体的には言語処理系および…… いや言語処理系くらいしかないな。しかしながら、言語処理系を実装するにあたってRustを選択するのは一般的な選択肢なので、これはゆゆしき問題です。

gcクレートによるGC導入

GC機能を提供するクレートはいくつかありますが、何も考えずシングルスレッドでGCしたいだけならgcクレートが手軽です。

Rc<T>/RefCell<T>の代わりにgc::Gc<T>/gc::GcCell<T>を使用するだけでOK。管理したい型にはgc::Traceおよびgc::Finalize traitを実装する必要があります。deriveしたいときはgc_deriveクレートも追加してください。

// Gc<T>で管理したい値は Trace および Finalize traitを実装している必要がある。
// 単純な場合は自動で導出可能。
#[derive(Debug, Clone, PartialEq, Eq, Trace, Finalize)]
pub enum Value {
    Int(i32),
    Array(Gc<GcCell<Vec<Value>>>),
}

// 自分自身を要素とする配列
fn new_cycled_value() -> Value{
    let array = Value::Array(Gc::new(GcCell::new(Vec::new())));

    let Value::Array(inner) = &array else { panic!(); };
    inner.borrow_mut().push(array.clone());
    array
}

Trace trait

Trace traitはメモリ管理のために必要で、実装では自分が持っているフィールドのうちGc<T>を含むものを全部マークする必要があります。これはgc::custom_trace!マクロを使って実装することができます。第一引数には自身を参照するためのシンボル(this)、第二引数にはトレース処理の実装(必要なフィールドに対してmark()を呼ぶ)を指定します。

unsafe impl Trace for Value {
    custom_trace!(this, {
        match this {
            Value::Int(_) => {}
            Value::Array(x) => { mark(x) }
        }
    });
}

Finalize trait

Finalize traitはGCにおけるDrop相当で、メモリが回収されたときに実行したい処理を記述します。普通は必要ないので #[derive(Finalize)]で生成される空実装を使えばよし。

GCのタイミング

ゴミはGc::new()のタイミングで必要に応じて回収されますが、gc::force_collect();を呼ぶことで明示的に回収することも可能です。

GC機能を提供するその他のクレート

GC管理されたポインタの表現が一種類しかないもの(Rc<T>代替系、簡単)と二種類あるもの(Rootとそれ以外、パフォーマンスが良さそうだがAPIは面倒)に別れます。arenaとついてるのは後者。

boa_gc

Rustで書かれたJS処理系Boaに使用されているGCライブラリ。Boaは元々gcクレートを使用しており、それをベースにした独自実装に切り替えたという経緯があるため、APIはかなり似ています。独自機能としてはweak referenceおよびWeakMapがあります。

gc-arena

Lua VMのRust実装であるpiccoroや、RustによるFlash PlayerエミュレーターRuffleで使用されているGCライブラリ。

jsonnet-gcmodule

JSONテンプレート言語Jsonnetで使われているGCライブラリ。std::rc::Rc感覚で使えて、明示的に回収関数を呼ぶことで相互参照された値も回収される。

dumpster

こちらもRc感覚で使えるGCライブラリ。マルチスレッドにも対応。作者による解説

moving_gc_arena

gc-arenaと同じくGCポインタがusize一個で済むタイプ。APIはこちらのほうが楽そう。

safe-gc

unsafe一切なしでGCライブラリを作ってやろうという野心的なこころみ。作者による解説

その他

お前らはGCの実装が好きすぎる。

Discussion