为什么使用性能计数器获取与流程相关的数据导致如此多的GC?

时间:2016-06-14 18:42:41

标签: c# .net performance garbage-collection performancecounter

我有一个程序集,它监视在机器上运行的许多微服务的性能统计信息。代码使用性能计数器来获取和发布数据,如下所示:

_counters = new Dictionary<string, PerformanceCounter>
{
    ["System Memory Available Bytes"] = new PerformanceCounter { CategoryName = "Memory", CounterName = "Available Bytes", ReadOnly = true },
    ["System CPU Usage %"] = new PerformanceCounter { CategoryName = "Processor", CounterName = "% Processor Time", InstanceName = "_Total", ReadOnly = true },

    ["Process CPU Usage %"] = new PerformanceCounter { CategoryName = "Process", CounterName = "% Processor Time", InstanceName = processName, ReadOnly = true },
    ["Process Thread Count"] = new PerformanceCounter { CategoryName = "Process", CounterName = "Thread Count", InstanceName = processName, ReadOnly = true },
    ["Process Private Bytes"] = new PerformanceCounter { CategoryName = "Process", CounterName = "Private Bytes", InstanceName = processName, ReadOnly = true },
    ["Process Working Set Bytes"] = new PerformanceCounter { CategoryName = "Process", CounterName = "Working Set", InstanceName = processName, ReadOnly = true },
    ["Process Virtual Bytes"] = new PerformanceCounter { CategoryName = "Process", CounterName = "Virtual Bytes", InstanceName = processName, ReadOnly = true },

    ["Contention Rate/Sec"] = new PerformanceCounter { CategoryName = ".NET CLR LocksAndThreads", CounterName = "Contention Rate / Sec", InstanceName = processName, ReadOnly = true },
    ["Contention Queue Peak Size"] = new PerformanceCounter { CategoryName = ".NET CLR LocksAndThreads", CounterName = "Queue Length Peak", InstanceName = processName, ReadOnly = true },
    ["Contention Total Count"] = new PerformanceCounter { CategoryName = ".NET CLR LocksAndThreads", CounterName = "Total # of Contentions", InstanceName = processName, ReadOnly = true },

    ["Induced GC Count"] = new PerformanceCounter { CategoryName = ".NET CLR Memory", CounterName = "# Induced GC", InstanceName = processName, ReadOnly = true },
    ["GC Handle Count"] = new PerformanceCounter { CategoryName = ".NET CLR Memory", CounterName = "# GC Handles", InstanceName = processName, ReadOnly = true },
    ["Finalization Survivors"] = new PerformanceCounter { CategoryName = ".NET CLR Memory", CounterName = "Finalization Survivors", InstanceName = processName, ReadOnly = true },
    ["LOB Size Bytes"] = new PerformanceCounter { CategoryName = ".NET CLR Memory", CounterName = "Large Object Heap size", InstanceName = processName, ReadOnly = true },
    ["Total Bytes in all Heaps"] = new PerformanceCounter { CategoryName = ".NET CLR Memory", CounterName = "# Bytes in all Heaps", InstanceName = processName, ReadOnly = true },
    ["Total Bytes Committed"] = new PerformanceCounter { CategoryName = ".NET CLR Memory", CounterName = "# Total committed Bytes", InstanceName = processName, ReadOnly = true },
    ["Total Bytes Reserved"] = new PerformanceCounter { CategoryName = ".NET CLR Memory", CounterName = "# Total reserved Bytes", InstanceName = processName, ReadOnly = true },
    ["Time in GC %"] = new PerformanceCounter { CategoryName = ".NET CLR Memory", CounterName = "% Time in GC", InstanceName = processName, ReadOnly = true },

    ["Time in JIT %"] = new PerformanceCounter { CategoryName = ".NET CLR Jit", CounterName = "% Time in Jit", InstanceName = processName, ReadOnly = true },
};

// Make sure we read each counter once, this is to set the sample start for 
// some of the counters that need a start, end invocation to return a value.
foreach (var counter in _counters.Values) { counter.NextValue(); }

然后我启动一个计时器,每隔 1 秒发布数据(为了简洁,我只将它们存储在变量中):

_timer = new Timer(1000);
_timer.Elapsed += OnTimerElapsed;
_timer.Start();

private void OnTimerElapsed(object sender, ElapsedEventArgs eArgs)
{
    var a = _counters["System CPU Usage %"].NextValue();
    var b = _counters["System Memory Available Bytes"].NextValue();
    //var c = _counters["Process CPU Usage %"].NextValue()/Environment.ProcessorCount;
    //var d = _counters["Process Thread Count"].NextValue();
    //var e = _counters["Process Private Bytes"].NextValue();
    //var f = _counters["Process Working Set Bytes"].NextValue();
    //var g = _counters["Process Virtual Bytes"].NextValue();
    var h = _counters["Contention Rate/Sec"].NextValue();
    var i = _counters["Contention Queue Peak Size"].NextValue();
    var j = _counters["Contention Total Count"].NextValue();
    var k = _counters["Induced GC Count"].NextValue();
    var l = _counters["GC Handle Count"].NextValue();
    var m = _counters["Finalization Survivors"].NextValue();
    var n = _counters["LOB Size Bytes"].NextValue();
    var o = _counters["Total Bytes in all Heaps"].NextValue();
    var p = _counters["Total Bytes Committed"].NextValue();
    var q = _counters["Total Bytes Reserved"].NextValue();
    var r = _counters["Time in GC %"].NextValue();
    var s = _counters["Time in JIT %"].NextValue();
}

使用注释计数器运行程序集会导致预期的GC行为,每隔几秒只会收集gen 0个集合。但是,如果我将<{1}}中的任何计数器取消注释为c,那么我将获得一个完整的(ggen 0)集合 1 秒。我无法解释这种行为,发生了什么?

0 个答案:

没有答案