.netgarbage-collectionetwperfview

Difference in PerfView's GCStats and CollectionCount() results


I'm learning PerfView and tried GCStats report. I've created a simple app which does a lot memory allocation on the heap:

using System;
using System.Collections.Generic;


class Program
{
    static void Main(string[] args)
    {
        GcReport();
        const int size = 10 * 1024 * 1024;
        var list = new List<int>();
        for (int i = 0; i < size; i++)
        {
            list.Add(i);
        }

        for (int i = 0; i < size; i++)
        {
            object obj1 = list[i];
            object obj2 = list[i];

            if (obj1 == obj2)
                Console.WriteLine("Match found");
        }

        GcReport();  // <-- results are shown below 
    }

    private static void GcReport()
    {
        Console.WriteLine($"Gen0: {GC.CollectionCount(0)}");
        Console.WriteLine($"Gen1: {GC.CollectionCount(1)}");
        Console.WriteLine($"Gen2: {GC.CollectionCount(2)}");
    }
}

Here is how I configure Run dialog in PefrView:enter image description here

Here is a PerfView's GCStats report: PerfView's GCStats report

And here is a peace of PerfView's log file, which shows results of second GcReport() method: enter image description here

As you can see, numbers of GC collections are different in PerfView's report and in Console Log results. Can somebody explain, why numbers are different?


Solution

  • The main difference in the reporting is that the GCReport shows the number for each EXACTLY generation and the GC.CollectionCount shows the number of GCs of a particular generation OR HIGHER. Thus GC.CollectionCount(0) is ALL GCS (that is Gen0, or Gen1 or Gen2), and notice they agree above.

    There is a discrepancy with the number of Gen 2 (if the output would have said Gen 2 count = 3 instead of 4, PerfView and the counts would be completely consistent).

    This could easily be some 'boundary' issue (a Gen 2 started but did not complete). I can only speculate at this point. However you can figure this out exactly if you wish. Create a EventSource (see my blog entry 'Logging ETW events in C#: System.Diagnostics.Tracing.EventSource') and log the GC counts frequently as you allocate. Then you can look at the 'Events' view and see all the GCs and the GCCounts and you can determine why exactly there is any discrepancy.