2017-02-19 8 views
0

メモリリークをテストするためのユニットテストを作成しようとしています。再現 手順:、WeakReferenceを使用してメモリリークのユニットテスト中に異常な動作が発生しました

~TestClass() { Console.WriteLine("TestClass instance finalized");} 

と私はファイナライザがアサート場合にはGCコマンドの一部として呼び出されることに気づいたが、私は、ifの条件に置き換えるとき:

TestClass test = new TestClass(); 
    WeakReference reference = new WeakReference(test, true); 

    test = null; 

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

    Debug.Assert(reference.Target == null, "Memory Leak"); // This works 

    //Replacing the above line with following, I see "Memory Leak" being printed. 

    if (reference.Target != null) 
    { 
     Console.WriteLine("Memory Leak"); 
    } 

私は、ファイナライザを追加しましたファイナライザはGCコマンドの一部として呼び出されないため、参照のターゲットはまだ生きています。ファイナライザは、プログラムが存在する前にのみ呼び出されます。

予想される動作:

if(reference.Target != null) Console.WriteLine("Memory Leak"); 

動作するはずです。

実際の動作:

Debug.Assert(reference.Target == null, "Memory Leak"); 

作品が、

if(reference.Target != null) Console.WriteLine("Memory Leak"); 

は、 "メモリリーク"

答えて

0

を印刷して、私は、この問題の根本的な原因を発見した作品はありません。このコードはリリースビルド構成では正常に動作しますが、デバッグでは動作しません(これは私が実行していたものです)。

「テスト」オブジェクトへの参照を保持するプロパティTargetを持つメンバ「参照」が存在するため、「テスト」がGCedされていない理由です。ウォッチウィンドウのようなデバッガツールを使ってこれを見ることができるようにするため、コンパイラはそれを生かしています。 WeakReferenceインスタンス(および対応するif条件)を取り除くと、デバッグモードでもGC'edされていることがわかります。また、Debug.Assertで "reference"を使用すると、targetへの参照が保持されず、 "test"がGCされるようになります。

リリースモードでは、コンパイラJITがコードをコンパイルして "test"変数を取り除く(なぜなら、nullに割り当てられているため)、 "test"がGCされている理由がありません。コード内のどこにでも参照してください。これによりGCが可能になります。 "reference"は "test"オブジェクトに対する弱い参照であるため、それを保持せず、GC'edされ、したがって、リリースモードでif条件が機能します。