参照カウント参照カウント(さんしょうカウント、英: reference counting)は、メモリオブジェクトのライフサイクル(寿命)管理に使用される方式のひとつ。ガベージコレクションの実装方法およびガベージコレクタの動作方法のひとつとしても利用される。また、コピーオンライトの実装方法としても多用される。 処理の概要
共有された単一のオブジェクトへの参照ではなく、独立したデータを擬似的に表現する場合は、下記の処理を追加する。
特徴長所
また、システムの空き時間(アイドル時)に動作する方式のガベージコレクションとは異なり、参照カウント方式は通例決定論的 (deterministic) に動作するため、オブジェクトの解放タイミングを確実に制御したい場合に有利である。 短所
特にマルチスレッド環境で参照カウントを利用する場合、スレッド間で共有されるオブジェクトのライフサイクルを正しく安全に管理するためには参照カウントの増減がスレッドセーフになるよう配慮しなければならないが、排他制御やアトミック操作などのロック機構は想定以上にコストの高い処理であり、大量に実行される場合は大きなオーバーヘッドを伴う[1]。 用途文字列オブジェクトの実装手段としては適しており、多くのシステムで採用されている。 これは、文字列であれば内部で他のオブジェクトを参照しないので、短所の多くには影響がないためである。 単純なビット列などのデータも同様に適している。 循環参照の問題点参照カウントには、循環参照によりデータを解放できなくなる(メモリリークが発生する)という問題がある。 例えばC++向けのBoost C++ライブラリあるいはC++11規格以降の標準C++ライブラリには、参照カウントベースのスマートポインタを実現するクラステンプレートとして、それぞれ #include <iostream>
#include <memory>
class A {
public:
std::shared_ptr<class B> m_refB;
A() {}
~A() {
std::cout << "Destructor of A is called." << std::endl;
}
};
class B {
public:
std::shared_ptr<class A> m_refA;
B() {}
~B() {
std::cout << "Destructor of B is called." << std::endl;
}
};
void doTest() {
std::shared_ptr<A> refA(new A());
std::shared_ptr<B> refB(new B());
refA->m_refB = refB;
refB->m_refA = refA;
} // ここで A および B のデストラクタが呼ばれなくなり、メモリリークする。
int main() {
doTest();
return 0;
}
循環参照によるメモリリークを回避するためには、利用を終えたタイミングで明示的に参照を解除するコードを記述するなどの方法があるが、ソースコードが煩雑になってしまい、スマートポインタの利点を打ち消してしまう。 この問題を解消するために、多くのプログラミング言語やソフトウェアライブラリあるいはシステムで弱い参照 (ウィークリファレンス、英: weak reference) が導入されている。弱い参照とは、参照カウントを増加させない参照である。例えばC++では 一方、マーク・アンド・スイープやコピーGCによるガベージコレクションでは、循環参照によるメモリリークの問題は発生しない。 なお、Javaや.NET Frameworkでは、いずれも参照カウントベースではないガベージコレクション方式を採用しており[2][3][4][5]、循環参照によるメモリリークは発生しない。例えば以下のJavaコードは合法であり、循環参照していたとしてもガベージコレクションの回収対象となる。 class A {
public B b;
}
class B {
public A a;
}
public class Test {
public static void doTest() {
A a = new A();
B b = new B();
a.b = b;
b.a = a;
} // 十分な時間が経過すれば、いずれ GC により回収される。
public static void main(String[] args) {
doTest();
}
}
ただし、非意図的オブジェクト保持(unintentional object retention)が引き起こすメモリリークを回避するために、通常の参照(強参照)の代わりに ウィキペディアでの例ウィキペディアの「孤立した記事」は、参照カウントが0のものを表示しているだけなので、孤立した記事だけから参照されている記事は孤立した記事と見なされていない。 実用例
脚注注釈出典
関連項目 |