2012-12-17 8 views
5

C#/ .NETのオブジェクトファイナライズとコレクションに関する学問的な質問があります。バックグラウンドの読み取りは、C#言語仕様、自動メモリー管理のセクション3.9です。オブジェクトがファイナライズされてもガベージコレクションされていない場合の弱参照動作

オブジェクトへの明示的な参照がない場合、オブジェクトがガベージコレクションされる可能性があります。それは「破壊の対象となります」となります。将来(ガベージコレクションを強制するなど)、オブジェクトのデストラクタが実行されます。

デストラクターで、オブジェクトへの参照を保存すると、オブジェクトはファイナライズされますが、コレクションには適格になりません。これにより、オブジェクトはファイナライズされた状態になりますが、収集されません。仕様の第3・9節にこれの例があります。

まだガベージコレクションされていないため、オブジェクトは実際にはまだ生きています。ただし、オブジェクトを参照しているWeakReferenceは、オブジェクトが収集されたことを示すIsAlive値falseを報告します。

コアの質問はこれです - 実際に報告するIsAliveプロパティは何ですか?値を読み取った直後に値がfalseになる可能性があるため、このプロパティでtrueの値を信頼することはできません。しかし、falseの値は信頼できるものであり、オブジェクトがガベージコレクションされたことを(ドキュメントに従って)意味するものです。この場合、IsAliveプロパティは私たちに何を伝えていますか?オブジェクトがファイナライズされているが収集されていない状態にあると確信しているため、オブジェクトがガベージコレクションされたかどうかは厳密にはありません。

ここでは動作を示すサンプルを示します。

public class Dog 
    { 
     public static Dog KeepDogRef; 



    public string Name { get; set; } 

    public Dog(string name) 
    { 
     Name = name; 
    } 

    ~Dog() 
    { 
     Console.WriteLine("Dog destructor for " + Name + " called"); 
     Dog.KeepDogRef = this; 
    } 

    public void Bark() 
    { 
     Console.WriteLine(Name + " : Woof"); 
    } 
} 

メインプログラムのコード。コードを実行すると、オリジナルのWeakReferenceがオブジェクトを再構成した後でも、IsAliveがfalseと報告されます。

static void Main() 
    { 
     Dog dog = new Dog("Bowser"); 

     WeakReference dogRef = new WeakReference(dog); 

     // Unref Bowser, now eligible for destruction 
     dog = null; 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 

     // Bowser no longer alive 
     Console.WriteLine(string.Format("Object still alive: {0}", dogRef.IsAlive)); 

     // Bowser alive again 
     Dog newRef = Dog.KeepDogRef; 
     newRef.Bark(); 
    } 
} 

答えて

7

あなたがWeakReferenceのドキュメントのすべてを読めば、それが可能な弱参照の複数のタイプがあることは明らかです。デフォルトでは、ショート弱参照が生成されます。しかし、長い弱参照を作成して、具体的には復活のシナリオを説明することもできます。 TrackResurrectionのドキュメントから

は、それが確定された後、現在の弱い参照オブジェクトによって参照されるオブジェクトが追跡されるかどうかの表示を取得します。

trueの場合、弱参照は長い弱参照で、WeakReferenceコンストラクタのtrackResurrectionパラメータにtrueが指定されています。

IsAliveプロパティを解釈する前に、弱い参照のこの部分を理解しておく必要があると思います。

+0

これは答えのようです。短い弱参照の場合、弱参照のTargetは、ファイナライザが呼び出されるとすぐにnullになります。弱い参照が長い場合は、オブジェクトが実際に収集されたときにのみnullになります。 MSDNのドキュメントは、これについては少し濁っています。短い対長いドキュメントは明らかですが、IsAliveプロパティのドキュメントはオブジェクトが収集されたときにIsAliveがfalseになるという点で完全に正確ではありません。技術的には、短い弱参照の場合、オブジェクトがファイナライズされたときに、実際に収集される前にのみ、オブジェクトは偽になります。 –

+3

@SeanSexton:わずかな修正:弱参照は、オブジェクトがコレクションに適格であることを通知してファイナライザが存在するとすぐに無効化され、ファイナライザメソッドが最初に実行されるオブジェクトのリストに追加されます機会。ファイナライザは通常、その後すぐに実行されますが、任意に遅延される可能性があります。しかし、オブジェクトをターゲットとする短い「WeakReference」は、オブジェクトが放棄されるとすぐに無効になりますが、実際にファイナライザがいつ実行されるかには関係なく無効になります。 – supercat

+0

BTWはかなり厄介なものですが、長い弱い参照では特に厄介ですが、WeakReferenceとそのターゲットの両方への参照が存在するとしても、ファイナライズの対象となる弱参照は無効になります。このため、長い弱参照を使用してオブジェクトが正常に死んでいることを確認するコードでは、静的参照を 'WeakReference'のどこかに作成し、他のオブジェクトに周期的に' WeakReference'まだ何か有用なことをしていて、いったん静的な参照がいなくなると、その静的な参照を削除します – supercat

関連する問題