PerfView 的 GCStats 和 CollectionCount() 结果的差异

Difference in PerfView's GCStats and CollectionCount() results

我正在学习 PerfView 并尝试使用 GCStats 报告。 我创建了一个简单的应用程序,它在堆上分配了大量内存:

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

以下是我在 PefrView 中配置 运行 对话框的方法:

这是 PerfView 的 GCStats 报告:

这里是 PerfView 的日志文件,它显示了第二个 GcReport() 方法的结果:

如您所见,PerfView 的报告和控制台日志结果中的 GC 收集次数不同。有人可以解释一下,为什么数字不同?

报告中的主要区别在于 GCReport 准确显示每一代的数量,而 GC.CollectionCount 显示特定代或更高的 GC 数量。因此 GC.CollectionCount(0) 是所有 GCS(即 Gen0、Gen1 或 Gen2),请注意它们在上面是一致的。

第 2 代的数量存在差异(如果输出显示第 2 代计数 = 3 而不是 4,PerfView 和计数将完全一致)。

这很可能是一些 'boundary' 问题(第 2 代开始但未完成)。我现在只能推测。但是,如果您愿意,您可以准确地解决这个问题。创建一个 EventSource(请参阅我的博客条目 'Logging ETW events in C#: System.Diagnostics.Tracing.EventSource')并在分配时频繁记录 GC 计数。然后您可以查看 'Events' 视图并查看所有 GC 和 GCCounts,然后您可以确定为什么存在任何差异。