4

コードがガベージを生成するかどうかを検出したかったのです。そこで、次の単体テストを作成しました。

[TestClass]
public class AllocationTest
{
    int[] generationCollections = new int[3];

    [TestMethod]
    public void TestGarbageGeneration()
    {
        generationCollections[0] = GC.CollectionCount(0);
        generationCollections[1] = GC.CollectionCount(1);
        generationCollections[2] = GC.CollectionCount(2);

        // Test for garbage here

        for (int generation = 0; generation < generationCollections.Length; generation++)
        {
            Assert.AreEqual(GC.CollectionCount(generation), generationCollections[generation]);
        }
    }
}

問題のコードを「ここでガベージをテストしてください」というコメントがある場所に配置しましたが、結果は予測できません。これは、GC が別のスレッドで実行され、テスト以外のコードによっていつでもトリガーされる可能性があるためです。

テスト コードの前後で GC.Collect を強制的にコレクションを実行しようとしましたが、コレクション カウントが常に増加するため、テストは常に失敗することに気付きました。

単体テストでガベージをテストする有意義な方法はありますか?

4

2 に答える 2

1

WMemoryProfilerを使用して、作成された追加の型の数を確認できます。独自のプロセスをプロファイリングすると、追加で作成されたすべてのタイプと、レポートを生成するために WMemoryProfiler によって使用されるいくつかのインスタンスが取得されます。

別のプロセスを使用して管理されたヒープを監視するか、自分のタイプのみに制限することで回避できます。メモリをリークすると、作成した追加のインスタンスで通常どおり表示されます。

  using (var dumper = new InProcessMemoryDumper(false,false))
  { 
     var statOld = dumper.GetMemoryStatistics();

     // allocaton code here
     var diff = dumper.GetMemoryStatisticsDiff(statOld);

    foreach (var diffinst in diff.Where(d => d.InstanceCountDiff > 1))
    {
        Console.WriteLine("Added {0} {1}", diffinst.TypeName, diffinst.InstanceCountDiff);
    }
  }

一時オブジェクトが使用したメモリ量を把握している場合は、CLR によって生成された ETL トレースを使用する PerfView などのプロファイリング API またはツールを使用する必要があります。GCの場合、彼のような特定のものをプログラムで有効にする必要があります。あなたの場合もGCAllocationTick_V1イベントが興味深いと思います。

diff を取得する前にオブジェクトへの参照を保持しておくと、オブジェクト グラフが消費するメモリ量を十分に理解できます。

于 2013-04-20T21:00:51.837 に答える
1

あなたがしようとすることができるのは、実際に次のようにアサートする前に、まったく同じロジックを使用して GC 状態をダンプすることです。

    // do some logic

    // GC.Collect, Thread.Sleep, ...

    currentCollections[0] = GC.CollectionCount(0);
    currentCollections[1] = GC.CollectionCount(1);
    currentCollections[2] = GC.CollectionCount(2);

その後、これらのダンプされた値でアサートします (ところで、アサーションの最初のパラメーターは予期され、2 番目のパラメーターは実際のものです)

    for (int generation = 0; generation < generationCollections.Length; generation++)
    {
        Assert.AreEqual(generationCollections[generation], currentCollections(generation));
    }

したがって、これほとんどの場合に機能する可能性がありますが、GCに何かをさせる方法はありません-何かをするように頼んでから、信じて待つだけです...

于 2013-04-20T21:02:08.060 に答える