参照カウントとは? わかりやすく解説

参照カウント

出典: フリー百科事典『ウィキペディア(Wikipedia)』 (2024/03/04 18:50 UTC 版)

参照カウント(さんしょうカウント、: reference counting)は、メモリオブジェクトのライフサイクル(寿命)管理に使用される方式のひとつ。ガベージコレクションの実装方法およびガベージコレクタの動作方法のひとつとしても利用される。また、コピーオンライトの実装方法としても多用される。

処理の概要

  • すべてのオブジェクト(メモリ上に置かれているデータの単位)に対して、参照カウントと呼ばれる整数値を付加しておく。これは、このオブジェクトへの参照(あるいはポインタ)がシステム全体にいくつ存在しているかを数えるものである。
  • オブジェクトへの参照が変化するたびにこの値は随時書き換わる。
  • 参照カウントが0になったものについては破棄が許される。ただし、ファイルキャッシュのように参照カウントが0になっても直ちにオブジェクトを破棄せず、再利用に備えてリソースの容量が許す限り保存してもかまわない。この場合、オブジェクトを破棄するための判断には別の基準が必要となる。

共有された単一のオブジェクトへの参照ではなく、独立したデータを擬似的に表現する場合は、下記の処理を追加する。

  • オブジェクトのコピーが要求されても、実際にはコピーを行わず元のオブジェクトへの参照を返し、参照カウントに1加える。
  • オブジェクトの変更が行われる場合は、以下の手順で行う
    • 参照カウントが1であればそのまま書き換える。
    • 参照カウントが2以上であれば、元のオブジェクトをコピーして参照カウントが1の新オブジェクトを作成し、それを書き換える。元のオブジェクトの参照カウントは1減らす。

特徴

長所

  • 処理が単純であり、高速である。
  • オブジェクトを多数生成し、すぐに参照を切るような処理においても、参照がなくなったことがその場で検知され、迅速に破棄が起きる。利用できるメモリが少ない状況では大きな利点となる。
  • ガベージコレクタのためのスレッドやプロセスを必要としない。
  • ガベージコレクションとコピーオンライトを同時に実装できる。

また、システムの空き時間(アイドル時)に動作する方式のガベージコレクションとは異なり、参照カウント方式は通例決定論的 (deterministic) に動作するため、オブジェクトの解放タイミングを確実に制御したい場合に有利である。

短所

  • オブジェクト同士が互いに参照しあうなど、参照が循環している場合、参照カウントが0にならないためにオブジェクトが破棄されないという問題がある。詳しくは後述の#循環参照の問題点を参照のこと。
  • 単純な実装では大量のオブジェクトが一斉に解放されることがあり、CPUの空き時間を利用してガベージコレクションを行う方法と比べると、処理が遅くなる場合もある。
    • コンテナオブジェクトなど、解放されるオブジェクトが、多くのオブジェクトを参照している場合に起こりやすい。
  • 対象オブジェクトが小さく、コピーが頻繁に行われるような場合は、参照カウントの空間的・時間的オーバーヘッドが問題となる場合がある。

特にマルチスレッド環境で参照カウントを利用する場合、スレッド間で共有されるオブジェクトのライフサイクルを正しく安全に管理するためには参照カウントの増減がスレッドセーフになるよう配慮しなければならないが、排他制御アトミック操作などのロック機構は想定以上にコストの高い処理であり、大量に実行される場合は大きなオーバーヘッドを伴う[1]

用途

文字列オブジェクトの実装手段としては適しており、多くのシステムで採用されている。 これは、文字列であれば内部で他のオブジェクトを参照しないので、短所の多くには影響がないためである。

単純なビット列などのデータも同様に適している。

循環参照の問題点

参照カウントには、循環参照によりデータを解放できなくなる(メモリリークが発生する)という問題がある。

例えばC++向けのBoost C++ライブラリあるいはC++11規格以降の標準C++ライブラリには、参照カウントベースのスマートポインタを実現するクラステンプレートとして、それぞれboost::shared_ptrあるいはstd::shared_ptrが用意されているが、これを使って自己参照あるいは相互参照を持つクラスを定義してしまうと、参照カウントが適切に減らされずに互いのインスタンスが解放されなくなってしまう。

#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++ではboost::weak_ptrあるいはstd::weak_ptrなどが該当する。

一方、マーク・アンド・スイープやコピー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)が引き起こすメモリリークを回避するために、通常の参照(強参照)の代わりにjava.lang.ref.WeakReferenceのような弱参照クラスのインスタンスを使うこともある[6]

ウィキペディアでの例

ウィキペディアの「孤立した記事」は、参照カウントが0のものを表示しているだけなので、孤立した記事だけから参照されている記事は孤立した記事と見なされていない。

実用例

  • マイクロソフトComponent Object Model (COM) におけるCOMオブジェクトは参照カウント方式で管理される。
  • プログラミング言語Objective-CおよびSwiftのオブジェクトは参照カウント方式で管理される。
  • プログラミング言語Perlのガベージコレクタは参照カウント方式を用いている。
  • プログラミング言語Pythonのガベージコレクタは主に参照カウント方式を用いている。
ただし、補助的に(伝統的なマーク&スイープとは逆順の探索アルゴリズムによる)世代別GCを併用している[7][8]
  • プログラミング言語C++の規格C++11以降には、参照カウントでオブジェクトを管理するためのクラステンプレートとしてstd::shared_ptrが存在する。
  • Boost C++ライブラリboost::shared_ptrおよびboost::shared_array[注釈 1]
参照カウントの増減処理をカスタマイズできるboost::intrusive_ptrもある。

脚注

注釈

  1. ^ Boost 1.53.0でboost::shared_ptrが配列にも対応したため[9]boost::shared_arrayは非推奨となっている[10]

出典

関連項目


参照カウント

出典: フリー百科事典『ウィキペディア(Wikipedia)』 (2022/04/27 10:00 UTC 版)

ガベージコレクション」の記事における「参照カウント」の解説

オブジェクト参照するポインタの数を数え参照するポインタの数がゼロになった解放する方法循環参照問題がある。解放集中したときに、単純な実装だと停止時間が長くなる

※この「参照カウント」の解説は、「ガベージコレクション」の解説の一部です。
「参照カウント」を含む「ガベージコレクション」の記事については、「ガベージコレクション」の概要を参照ください。

ウィキペディア小見出し辞書の「参照カウント」の項目はプログラムで機械的に意味や本文を生成しているため、不適切な項目が含まれていることもあります。ご了承くださいませ。 お問い合わせ


英和和英テキスト翻訳>> Weblio翻訳
英語⇒日本語日本語⇒英語
  

辞書ショートカット

すべての辞書の索引

「参照カウント」の関連用語

参照カウントのお隣キーワード
検索ランキング

   

英語⇒日本語
日本語⇒英語
   



参照カウントのページの著作権
Weblio 辞書 情報提供元は 参加元一覧 にて確認できます。

   
ウィキペディアウィキペディア
All text is available under the terms of the GNU Free Documentation License.
この記事は、ウィキペディアの参照カウント (改訂履歴)の記事を複製、再配布したものにあたり、GNU Free Documentation Licenseというライセンスの下で提供されています。 Weblio辞書に掲載されているウィキペディアの記事も、全てGNU Free Documentation Licenseの元に提供されております。
ウィキペディアウィキペディア
Text is available under GNU Free Documentation License (GFDL).
Weblio辞書に掲載されている「ウィキペディア小見出し辞書」の記事は、Wikipediaのガベージコレクション (改訂履歴)の記事を複製、再配布したものにあたり、GNU Free Documentation Licenseというライセンスの下で提供されています。

©2025 GRAS Group, Inc.RSS