参照カウント
出典: フリー百科事典『ウィキペディア(Wikipedia)』
(参照カウント法から転送)
参照カウント(さんしょうカウント、reference counting)は、ガベージコレクタの動作方法の一つ。 また、コピーオンライトの実装方法としても多用される。
処理の概要
- すべてのオブジェクト(メモリ上におかれているデータの単位)に対して、参照カウントと呼ばれる整数値を付加しておく。これは、このオブジェクトへのポインタがシステム全体にいくつ存在しているかを数えるものである。
- オブジェクトへの参照が変化するたびにこの値は随時書き換わる。
- 参照カウントが0になったものについては破棄が許される。
共有された単一のオブジェクトへの参照ではなく、独立したデータを擬似的に表現する場合は、下記の処理を追加する。
- オブジェクトのコピーが要求されても、実際にはコピーを行わず元のオブジェクトへの参照を返し、参照カウントに1加える。
- オブジェクトの変更が行われる場合は、以下の手順で行う
- 参照カウントが1であればそのまま書き換える。
- 参照カウントが2以上であれば、元のオブジェクトをコピーして参照カウントが1の新オブジェクトを作成し、それを書き換える。元のオブジェクトの参照カウントは1減らす。
特徴
長所
- 処理が単純であり、高速である。
- オブジェクトを多数生成し、すぐに参照を切るような処理においても、参照がなくなったことがその場で検知され、迅速に破棄が起きる。利用できるメモリが少ない状況では大きな利点となる。
- ガベージコレクタのためのスレッドやプロセスを必要としない。
- ガベージコレクションとコピーオンライトを同時に実装できる。
短所
- オブジェクト同士が互いに参照しあうなど、参照が循環している場合、参照カウントが0にならないためにオブジェクトが破棄されないという問題がある。(詳しくは後述)
- 単純な実装では大量のオブジェクトが一斉に解放されることがあり、CPUの空き時間を利用してガベージコレクションを行う方法と比べると、処理が遅くなる場合もある。
- コンテナオブジェクトなど、開放されるオブジェクトが、多くのオブジェクトを参照している場合に起こりやすい。
- 対象オブジェクトが小さく、コピーが頻繁に行われるような場合は、参照カウントの空間的・時間的オーバーヘッドが問題となる場合がある。
用途
文字列オブジェクトの実装手段としては適しており、多くのシステムで採用されている。 これは、文字列であれば内部で他のオブジェクトを参照しないので、短所の多くには影響がないためである。
単純なビット列などのデータも同様に適している。
循環参照の問題点
参照カウントには、循環参照により到達不能なデータでも解放できないという問題がある。
class A {
public B b;
}
class B {
public A a;
}
public class Test {
public static void main(String[] args) {
A a = new A(); // *1*
B b = new B(); // *2*
a.b = b;
b.a = a;
a = null;
b = null;
// *1*、*2*で作成したAとBのオブジェクトは到達不可能にもかかわらず、参照カウントは1
}
}
この問題を防ぐためには、多くの言語・システムでウィークリファレンスが導入される。 ウィークリファレンスとは、参照カウントを増加させないポインタである。
ウィキペディアでの例
ウィキペディアの「孤立した記事」は、参照カウントが0のものを表示しているだけなので、孤立した記事だけから参照されている記事は孤立した記事と見なされていない(これも循環参照の例である)。
上で述べた問題を回避する方法としてマーク・アンド・スイープがある。
実用例
- マイクロソフトのComponent Object ModelにおけるCOMオブジェクトは参照カウント方式で管理される。
- プログラミング言語Perlのガベージコレクタは参照カウント方式を用いている。
- プログラミング言語Pythonのガベージコレクタは主に参照カウント方式を用いている。
- プログラミング言語C++には、参照カウントでオブジェクトを管理するためのshared_ptr<>が存在する。
- Boost C++ Library の shared_ptr<> 及び shared_array<>。
- POCO C++ Libraries の SharedPtr。
- GLibに含まれるオブジェクトシステムGObjectは参照カウント方式で管理を行う。
- ファイルシステムにおけるハードリンク