Garbage Detection in Unit Test

I wanted to determine if my code generated garbage. So I created the following unit test.

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

I put the code in the question, where is the comment "Test for garbage here" and the results are unpredictable. I understand that this is due to the fact that the GC runs in a separate thread and can be called by code other than my test at any time.

I tried GC.Collect to force collections to run before and after the test code, but then realized that this always increases the collection counter, so the test always fails.

Is there a sensible way to check for garbage in unit test?

+4
source share
2 answers

You can use WMemoryProfiler to find out how many additional types have been created. If you profile your own process, you will get all additional types created + some instances used by WMemoryProfiler to generate the report.

You can work through a separate process to control your managed heap or limit yourself to just your types. If you skip memory, you will usually see it in additional instances you created.

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

If you use how many temporary memory objects you used, you will need to use some profiling Api or tools such as PerfView, which uses the ETL traces generated by the CLR. For GC, you need to programmatically enable certain things, such as it. I think the GCAllocationTick_V1 event would be interesting in your case.

If you keep a reference to your object before trying to get diff, you get a pretty good idea of ​​how much memory your graphic will consume.

+1
source

What you can try to do is use exactly the same logic to reset the state of the GC to the actual type statement

  // do some logic // GC.Collect, Thread.Sleep, ... currentCollections[0] = GC.CollectionCount(0); currentCollections[1] = GC.CollectionCount(1); currentCollections[2] = GC.CollectionCount(2); 

and then approve with these reset values ​​(BTW in the statements, the first parameter is expected, and the second is the actual one)

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

So this one can work in most cases, but there is no way to get the GC to do something - you can just ask it to do something, and then wait in faith ...

+1
source

All Articles