C# 在单元测试中检测垃圾

C# 在单元测试中检测垃圾,c#,.net,garbage-collection,C#,.net,Garbage Collection,我想检测我的代码是否生成垃圾。所以我创建了下面的单元测试 [TestClass] 公共类分配测试 { int[]generationCollections=新int[3]; [测试方法] 公共无效测试垃圾生成() { generationCollections[0]=GC.CollectionCount(0); generationCollections[1]=GC.CollectionCount(1); generationCollections[2]=GC.CollectionCount(2

我想检测我的代码是否生成垃圾。所以我创建了下面的单元测试

[TestClass]
公共类分配测试
{
int[]generationCollections=新int[3];
[测试方法]
公共无效测试垃圾生成()
{
generationCollections[0]=GC.CollectionCount(0);
generationCollections[1]=GC.CollectionCount(1);
generationCollections[2]=GC.CollectionCount(2);
//在这里检测垃圾
对于(int generation=0;generation
我对代码中“testforgarbage-here”注释的位置提出了质疑,结果是不可预测的。我的理解是,这是由于GC在一个单独的线程上运行,并且可以在任何时候由测试以外的代码触发


我尝试在测试代码前后强制运行GC.Collect收集,但后来意识到这总是会增加收集计数,所以测试总是失败

是否有一种有意义的方法来测试单元测试中的垃圾?

您可以使用它来了解创建了多少其他类型。如果您分析自己的流程,您将获得所有附加创建的类型以及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);
    }
  }
如果您想知道临时对象使用了多少内存,则需要使用一些分析Api或工具,如PerfView,它使用CLR生成的ETL跟踪。对于GC,您需要通过编程启用特定的东西,比如他的。我想这件事对你来说也会很有趣


如果您在尝试获取差异之前保留对对象的引用,您将非常清楚对象图将消耗多少内存。

您可以尝试的是在实际断言like之前使用完全相同的逻辑转储GC状态

    // do some logic

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

    currentCollections[0] = GC.CollectionCount(0);
    currentCollections[1] = GC.CollectionCount(1);
    currentCollections[2] = GC.CollectionCount(2);
然后使用这些转储值进行断言(顺便说一句,断言中的第一个参数是预期的,第二个是实际的)

for(int generation=0;generation

因此,这个可能在大多数情况下都有效,但是没有办法让GC做一些事情-你可以要求它做一些事情,然后满怀信心地等待…

可能重复“那总是增加收集计数”,是的,但只是+1??我犯了一个错误。注释“testforgarbage here”是可能生成垃圾的代码所在的位置。实际的测试是断言。
    for (int generation = 0; generation < generationCollections.Length; generation++)
    {
        Assert.AreEqual(generationCollections[generation], currentCollections(generation));
    }