TL;DR
リソースを指す参照やポインタの数を記録しておき、数が 0 になったときにそのリソースを解放する手法。ガベージコレクションの方式の 1 つとしても使われる。
なぜ必要か
1 つの値を複数の場所から共有したいとき、誰が最後に使い終わったかを数で管理できる。Wikipedia によると、参照されなくなった値はすぐに回収されるので、長い停止が起きにくく、値の寿命がはっきり決まる。
仕組み
参照を複製するとカウントを 1 増やし、参照を破棄すると 1 減らす。カウントが 0 になったら値を解放する。
Rust の Rc<T> では、clone で同じ値を指すポインタが増え、最後の Rc が破棄されたときに中の値もドロップされる。Rc はアトミックでないカウントを使うのでオーバーヘッドが小さい代わりに、Send を実装せず、スレッド間では送れない。マルチスレッドではアトミックにカウントする Arc を使う(std::rc)。
例
- Rust の
RcとArc。値を変更したいときは、Rc<RefCell<T>>やArc<Mutex<T>>のように内部可変性を持つ型と組み合わせる。 - Lean は、C にコンパイルしたコードでオブジェクトを参照カウントで管理する。参照カウントを見て、データ構造の更新を破壊的な更新に最適化できる。
- Wikipedia によると、Python や Swift も参照カウントを使う。
注意点
参照カウントだけに頼る仕組みは、循環参照した値を解放できない。Rust では、カウントを増やさない弱い参照(Weak)で循環を断ち切る。また、カウントの更新にはコストがかかり、並行処理ではアトミックに更新する必要がある。