我想检测我的代码是否产生垃圾。所以我创建了以下单元测试。
[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 在测试代码之前和之后强制运行集合,但后来意识到这总是会增加集合计数,因此测试总是失败。
是否有一种有意义的方法来测试单元测试中的垃圾?
最佳答案
您可以使用 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);
}
}
如果您想要了解临时对象使用了多少内存,您将需要使用一些性能分析 API 或类似 PerfView 的工具,它确实使用 CLR 生成的 ETL 跟踪。对于 GC,您需要以编程方式启用像他这样的特定内容。我认为 GCAllocationTick_V1您的事件也会很有趣。
如果在尝试获取差异之前确实保留了对对象的引用,那么您将很好地了解对象图将消耗多少内存。
关于c# - 在单元测试中检测垃圾,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16124461/