2011-11-30 4 views
8

私はデリゲートを保持するクラスを持っています。代議員のGC、何が欠けていますか? (私のデリゲートは収集されません)

私が評価したら、デリゲートを呼び出すことによって、デリゲートへの参照がクリアされ、コレクションの対象となることが期待されます。結局のところ、匿名メソッドとして構築されていれば、ローカル変数の世界を握っているかもしれません。

これを確認するために単体テストを構築しようとしましたが、私が計画した方法ではうまくいきませんでしたが、代わりにWeakReference(ここではテスト目的で使用しました)他の仮定は、水を保持しません。

私はそれを想定したあなたはLINQPad

void Main() 
{ 
    WeakReference wr; 
    Lazy<int> l; 
    CreateTestData(out wr, out l); 

    wr.IsAlive.Dump();     // should be alive here 

    GC.Collect(); 
    GC.WaitForPendingFinalizers(); 
    GC.Collect(); 

    wr.IsAlive.Dump();     // and alive here as well 
    l.Value.Dump();      // but now we clear the reference 

    GC.Collect();      // so one of these should collect it 
    GC.WaitForPendingFinalizers(); 
    GC.Collect(); 

    wr.IsAlive.Dump();     // and then it should be gone here 
    GC.KeepAlive(l); 
} 

void CreateTestData(out WeakReference wr, out Lazy<int> l) 
{ 
    Func<int> f =() => 10; 
    wr = new WeakReference(f); 
    l = new Lazy<int>(f); 
} 

public class Lazy<T> 
{ 
    private Func<T> _GetValue; 
    private T _Value; 

    public Lazy(Func<T> getValue) 
    { 
     _GetValue = getValue; 
    } 

    public T Value 
    { 
     get 
     { 
      if (_GetValue != null) 
      { 
       _Value = _GetValue(); 
       _GetValue = null; 
      } 
      return _Value; 
     } 
    } 
} 

で実行することができ、このコードを見てみましょう:

  1. かかわらず、デバッグビルドの、デバッガ添付、私は、デリゲートを作成したので、私が戻ってきた別のメソッドは、WeakReferenceLazy<T>オブジェクトを除く、デリゲートを保持するものは何もありません
  2. 残された唯一の参照がWeakReference
  3. の1である場合と仮定し、 WeakReference
  4. につかまっそして、完全なガベージコレクションを強制される唯一の参照を減らすことになる、デリゲートへの参照を放棄する210オブジェクト
  5. はその後、デリゲートは、収集されるだろう、と私WeakReferenceは、オブジェクトがもはやコードの出力は、このように(コメント付き)であることが予想された

生きていることを示していないでしょう:

true // not gc'ed after construction 
true // not gc'ed after full GC, still beind held by Lazy<T> 
10 // value from calling delegate 
false // but is now gc'ed, Lazy<T> no longer has a reference to it 

しかし、その代わりに出力されます:

true 
true 
10 
true 

誰もが、私はここに欠けているものにいくつかの光を当てることができますか?

答えて

6

"問題"は、コンパイラが単一のデリゲートインスタンスを永久に再利用できることに気付いていることです。。コンテキストをキャプチャしません。暗黙的なthisの参照でもありません。だから、この:起こっているのを正確に知るために(オン最適化なしでまたはリフレクター)ILDASMのコードで

static Func<int> hiddenDelegate; 

static int HiddenMethod() 
{ 
    return 10; 
} 

void CreateTestData(out WeakReference wr, out Lazy<int> l) 
{ 
    if (hiddenDelegate == null) 
    { 
     hiddenDelegate = HiddenMethod; 
    } 

    Func<int> f = hiddenDelegate; 
    ... 
} 

ルック:

void CreateTestData(out WeakReference wr, out Lazy<int> l) 
{ 
    Func<int> f =() => 10; 
    ... 
} 

は、のようなものになっています。

+0

これは意味があります。デリゲートを変更して、結果を計算するためにローカル変数を使用しました。これは実際に収集されたものです。 –

+0

サイド質問:私は、同じ型の複数のデリゲートが同じ定数値を返すことに気付くほどスマートではないと仮定しています。一度作成してどこでも再利用できますか? –

+0

基本的に私の目標は、その特定のデリゲートが収集されたわけではなく、許可された場所でガベージコレクションを可能にするために、デリゲートへの参照が適切なタイミングで放棄されることを検証するテストを行うことでした。デリゲートを変更するだけで、その問題はわずかに解決され、テストは期待通りに実行されます。 –

関連する問題