2012-06-27 3 views
7

イベントプロパティを持つクラスがあるとします。このクラスをローカル・コンテキストでインスタンス化し、外部参照なしでイベントにラムダ式を割り当てると、インスタンスがガベージ・コレクションされないようにしますか?イベントに割り当てられたlambdaは所有オブジェクトのガベージコレクションを防止しますか?

{ 
    var o = new MyClass(); 
    o.MyClassEvent += (args) => {}; 
} 
// Will 'o' be eligible for garbage collection here? 
+1

これはGCに適しているはずです。私はこれを答えにするのに十分ではない。 –

+0

これは、他の関数(ラムダなど)をイベントにサブスクライブするのと違って動作する理由はわかりません。だから私はティムに同意する。 –

+0

[イベント処理に匿名の代理人を使用する場合のガベージコレクション]の可能な複製(http://stackoverflow.com/questions/371109/garbage-collection-when-using-anonymous-delegates-for-event-handling) –

答えて

5

いいえ、oは解放され、ラムダ機能も解放されます。他の場所からのoへの参照はありません。したがって、解放されるべきではありません。

1

ランタイムがそのコードブロックを離れると、オブジェクトへの参照がなくなるため、ガベージコレクションが行われます。

+0

ローカルストレージにこれ以上の参照がないことをどのように知っていますか? –

+0

何かへの参照があるかどうかは関係ありません。実際、ラムダはおそらくそのオブジェクトへの参照を持つヒープ割り当てオブジェクトであるため、あなたの主張は偽です。 GCにとって重要なのは、オブジェクトが*到達可能かどうかです。 – delnan

0

"ローカルコンテキスト"とは正確に何を意味しているかによって異なります。

static void highMem() 
{ 
    var r = new Random(); 
    var o = new MyClass(); 
    o.MyClassEvent += a => { }; 
} 
static void Main(string[] args) 
{ 
    highMem(); 
    GC.Collect(); //yes, it was collected 
} 

を:比較私の環境では

static void Main(string[] args) 
{ 
    var r = new Random(); 
    { 
     var o = new MyClass(); 
     o.MyClassEvent += a => { }; 
    } 
    GC.Collect(); //no, it wasn't collected 
} 

(デバッグビルド、VS 2010、Win7のx64の)、最初の1は、GCの対象だったとによって確認されたように、第2の1は(ありませんでしたMyClassには200MBのメモリが搭載され、タスクマネージャでチェックされています)。これは、コンパイラがメソッドの開始時にすべてのローカル変数を宣言しているためです。つまり、CLRではoは範囲外ではありませんが、C#コードでは使用できませんでした。

+1

'o'は範囲外ですが、スコープはガベージコレクションとはほとんど関係がありません。ライブ参照はほとんどありません。参照がスコープ内にある間に参照のスタック領域が使用されている場合、その参照は収集できます。場合によっては、操作が完了する前に収集することもできます。 –

2

短い答え、いいえ、oは解放されます。ご心配なく。

少し長い答え:

をあなたのコードは、多かれ少なかれ、次ん:

  1. 新しいMyClassの(o)への参照のためにそのスレッド上でいくつかのローカルストレージを作成します。
  2. 新しいMyClassを作成
  3. 新しいMyClassへの参照をoに保存します。
  4. ラムダから新しいデリゲートを作成します。
  5. イベントにデリゲートを割り当てます(oにはデリゲートへの参照が含まれています)。

この間に、GCはスレッドを停止して、どのオブジェクトがルートされているかどうかを調べることがあります。ルートは、スタティックまたはスレッドのローカル記憶域にあるオブジェクトです(これは、基本的に静的な形式のスレッド・ローカル・ストレージではなく、スタックによって実装された特定のスレッドの実行におけるローカル変数を意味します)。ルーテッドオブジェクトは、ルーツ、それらによって参照されるオブジェクト、それらによって参照されるオブジェクトなどです。根っこのオブジェクトは収集されません。残っているオブジェクトは、現在は無視されるファイナライザーとは関係ありません。

MyClassオブジェクトが作成された後も、スレッドのローカルストレージによってルートされていません。

デリゲートオブジェクトが作成された後は、スレッドのローカルストレージによってルートされていないか、またはその参照を持つMyClassによってルートされていません。

次に、次に何が起こりますか?

によって異なります。ラムダはMyClassを生かし続けることはありません(MyClassはそれを生かしていますが、MyClassが行くとラムダもそうです)。これは "Will 'o'がガベージコレクションの対象になると答えるだけでは不十分です。しかし、。

void Meth0() 
{ 
    var o = new MyClass(); 
    o.MyClassEvent += (args) => {}; 
}//o is likely eligible for collection, though it doesn't have to be. 

void Meth1() 
{ 
    int i = 0; 
    { 
    var o = new MyClass(); 
    o.MyClassEvent += (args) => {}; 
    }//o is likely not eligible for collection, though it could be. 
    while(i > 100000000);//just wasting time 
} 

void Meth2() 
{ 
    { 
    var o = new MyClass(); 
    o.MyClassEvent += (args) => {}; 
    int i = 0;//o is likely eligible for collection, though it doesn't have to be. 
    while(i > 100000000);//just wasting time 
    } 
} 

void Meth3() 
{ 
    { 
    var o = new MyClass(); 
    o.MyClassEvent += (args) => {}; 
    var x0 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x1 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x2 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x3 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x4 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x5 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x6 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x7 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x8 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x9 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x10 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    var x11 = new MyClass();//o is even more likely eligible for collection, though it doesn't have to be. 
    int i = 0; 
    while(i > 100000000);//just wasting time 
    } 
} 

Meth0は一見もっともシンプルですが、実際にはそうではありませんので、ここで再び取り上げます。 Meth1で

、実装はそうoがスコープではありませんが、実装はまだ使用されているローカルストレージを持っていますので、それは、もはや必要とされていないので、それは、あるとしてローカルストレージを残すべきです。 Meth2で

、実装「スコープ内」(それがスコープ内にまだあるにもかかわらず、収集する資格があるのでiことがoのために使用したのと同じローカル・ストレージを使用することができ、プログラマが行うことを選択できることを意味それと何か、しかし彼または彼女はそうしなかったし、コンパイルされたコードはそのような概念を必要としない)。

Meth3はストレージを再利用する可能性が高くなります。これは、一時的に使用されるため、すべてのストレージを先に設定するのではなく、より意味があるためです。

これらのものはありませんはこのようになるととなります。 Meth2とMeth3はどちらも、最初にこのメソッドに必要なすべてのストレージを確保することができます。メッシュ1は、ioの順番を変更することに違いがないため、ストレージを再利用できます。

Meth0は、呼び出し元のメソッドが次にローカルストレージを使用するかどうかに依存する可能性があるため、より複雑です(どちらも正当な実装です)。 IIRCでは、現在の実装では常にクリーンアップが行われていますが、わかりませんが、とにかく問題はありません。

スコープは関連するものではなく、コンパイラとそれ以降のJITterがオブジェクトに関連するローカルストレージを使用できるかどうかを示します。メソッドやプロパティが呼び出される前にオブジェクトをクリーンアップすることもできます(オブジェクトが削除されてもうまくいくので、メソッドとプロパティがthisやオブジェクトのフィールドのいずれかを使用しない場合) )。

関連する問題