2013-04-20 114 views
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在測試代碼之前和之後強制運行集合,但後來認識到總是會增加集合計數,所以測試總是失敗。

是否有一種有意義的方式來測試單元測試中的垃圾?

+0

可能重複[是否有可能配置單元測試內存使用情況?](http://stackoverflow.com/questions/2930172/is-it-可能的配置文件內存使用的單元測試) – 2013-04-20 19:49:14

+0

「總是增加收集計數」,是的,但只是通過+1 ?? – GameAlchemist 2013-04-20 20:14:39

回答

1

您可以使用WMemoryProfiler來了解創建了多少個附加類型。如果你分析自己的進程,你將得到所有附加的創建類型+ WMemoryProfiler使用的一些實例來生成報告。

你可以通過使用一個單獨的進程來監視你的managaed堆或通過限制你自己只有你的類型。如果你泄漏內存,你通常會在你創建的附加實例中看到它。

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); 
    } 
    } 

如果你是經過大量的內存臨時對象究竟是怎麼用你,你將需要使用一些分析API或工具,如PerfView其確實使用由CLR generaeted ETL痕跡。對於GC,您需要以編程方式啓用他的特定內容。我認爲GCAllocationTick_V1事件在你的情況下也會很有趣。

如果在嘗試獲取差異之前確實保留了對象的引用,那麼您將很好地理解對象圖將消耗多少內存。

1

你能嘗試做的是使用完全相同的邏輯實際上斷言像

// do some logic 

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

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

,之後做這些傾倒價值主張(順便說一句,主張第一個參數是之前轉儲GC狀態預期,而第二個是實際的)

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

所以這可以工作對於大多數情況,但目前還沒有辦法使GC做一些事情 - 你可能只是一個sk它做的東西,然後等待相信...

+0

我犯了一個錯誤。評論「測試垃圾在這裏」是可能會產生垃圾的代碼。實際的測試是斷言。 – RecursiveCall 2013-04-20 23:37:46