いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

.NET クラスライブラリ探訪-005 (System.WeakReference)

System.WeakReferenceクラスは弱い参照を表すクラスです。
このクラスはガベージコレクトと関わっていまして
通常、ガベージコレクトが発生した際ピープにあるオブジェクト
達が掃除されるのですが、どこかに一つでも参照が保持されている
場合は、ガベージコレクトの対象にはなりません。

これを強い参照といいます。まあ、通常の参照の状態です。


で、これだとまずいケースがたまにあります。
大量のデータを一括して処理するバッチ処理とかが当てはまるでしょうか。
そのような処理の場合、大抵リストなり辞書なりを用いて処理をしたりします。
ずっとリストなどにオブジェクトをため続けた場合、メモリ不足してしまう
パターンもあったりします。(作り方がまずいって言えばそれまでなんですが・・・)
メモリが枯渇しだしてくるとGCが走りますが、参照がリスト内に存在している限り
オブジェクトは廃棄されません。


そんなときの場合に、System.WeakReferenceを使ったりするときがあります。
このオブジェクトは、内部にターゲットとなるオブジェクトの参照を一つ持ちます。
通常、先ほど記述したように参照が保持されている限りオブジェクトはGCされないのですが
このクラスの場合は、ガベージコレクトの対象としてマークされます。


実際、開発してる際にこのクラスを使うことは少ないと思います。
私の場合は、javaの方ですが一回しか使ったことないです・・。
どちらかと言うと、フレームワークを作成したりする場合の方が結構使うと思います。


こんなわけであんまり自分自身も分かってないですが、とりあえずサンプル。

using System;

using Gsf.Research.ClassLibrary;

namespace Gsf.Research.ClassLibrary.System{

    /// <summary>
    /// System.WeakReferenceクラスのサンプルです。
    /// </summary>
    /// <remarks>
    /// System.WeakReferenceクラスは弱い参照を表します。
    /// 弱い参照とは、参照を保持しているけれどもガベージコレクトの
    /// 対象となる参照の事です。
    /// 通常の参照(強い参照)の場合は、自身のスコープが抜けても
    /// どこかで参照が保持されている場合、ガベージコレクトの
    /// 対象にはなりませんが、WeakReferenceを利用した場合は
    /// その場合もガベージコレクトの対象となります。
    /// 基本的なイメージは, javaの場合でいうとjava.lang.ref.WeakReferenceクラスと
    /// 同じです。
    ///
    /// 以下の2つのプロパティを主に使用します。
    /// -IsAlive --> 内部で保持している参照が生存しているかどうか
    /// -Target  --> 内部で保持する参照を取得・設定します
    ///
    /// </remarks>
    public class WeakReferenceResearch00 : IExecutable{

        /// <summary>
        /// サンプルデータクラスです。
        /// </summary>
        class A{
            public string name;

            public override string ToString(){
                return name;
            }
        }

        ////////////////////////////////////////////////////////////////
        // 検証を行うため、2つのフィールドを用意。
        // 一つは、そのままの強い参照(_a2), もう一つは弱い参照(_wr)
        //
        A             _a2;
        WeakReference _wr;

        /// <summary>
        /// 処理を実行します。
        /// </summary>
        public void Execute(){
            WeakReferenceResearch00 w = new WeakReferenceResearch00();

            w.Execute1();
            w.Execute2();

        }

        void Execute1(){
            //
            // _a2, _wrともに、ローカルスコープで
            // 生成したオブジェクトの参照を持つ。
            //
            A a  = new A();
            A a2 = new A();

            a.name  = "hoge";
            a2.name = "hoge2";

            _wr = new WeakReference(a);
            _a2 = a2;

            Console.WriteLine("Execute1() _a2={0}",         _a2);
            Console.WriteLine("Execute1() _wr.IsAlive={0}", _wr.IsAlive);
            Console.WriteLine("Execute1() _wr.Target={0}",  _wr.Target);

            //
            // [注意]その変数自身が存在しているスコープにいる場合は、
            //       WeakReferenceを使っていてもガベージコレクトされません。
            //
        }

        void Execute2(){

            // 強制ガベージコレクト
            //
            // この時点で、_wrの保持している参照が廃棄されます。
            GC.Collect();

            //
            // _a2(強い参照)は先ほどの参照を保持しているが、
            // _wr(弱い参照)はGCにかかり、廃棄されている。
            //
            Console.WriteLine("Execute2() _a2={0}",         _a2);
            Console.WriteLine("Execute2() _wr.IsAlive={0}", _wr.IsAlive);
            Console.WriteLine("Execute2() _wr.Target={0}",  _wr.Target);
        }

    }
}

ちなみに、javaの場合も同じようなクラスがありまして

java.lang.ref.WeakReference
java.lang.ref.SoftReference
java.lang.ref.PhantomReference
java.util.WeakHashMap

などというクラスが存在しています。



================================
過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。