I am trying to measure how much time was spent in GC
between two points in my application. Something like this:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
gcPerfCounter.NextValue();
// This is the part that I would like to measure
doStuff();
var timeSpentInGC = gcPerfCounter.NextValue();
However, I am not sure that this is the correct way of using this counter. In this post: Correct use of "% Time in GC" performance counter the answers said that it should be used like a stopwatch, that's why I called NextValue() before operation. I don't think that this is the case, beacuse it gave me the same results, when I deleted the first gcPerfCounter.NextValue()
line.
The MSDN article says about "% Time in GC" performance counter:
Displays the percentage of elapsed time that was spent performing a garbage collection since the last garbage collection cycle. https://msdn.microsoft.com/en-us/library/w8f5kw2e(v=vs.110).aspx
It confuses me, because I would think that since the last GC cycle
we spent zero time in GC
. So according to this description, this value should be always zero.
Could you explain me the meaning and the correct use of this performance counter in my case?
I agree that the description of the performance counter is confusing. To better understand what it counts here is the entire description from Performance Counters in the .NET Framework that you provided a link to:
Displays the percentage of elapsed time that was spent performing a garbage collection since the last garbage collection cycle. This counter usually indicates the work done by the garbage collector to collect and compact memory on behalf of the application. This counter is updated only at the end of every garbage collection. This counter is not an average; its value reflects the last observed value.
It is clearly stated that the counter is updated at the end of a garbage collection. Based on this fact I believe that you can use the following timeline to better understand the counter:
GC0 GC1 ----+-------+------------------+-------+---- Tstart0 Tend0 Tstart1 Tend1 | Not in GC | In GC | +------------------+-------+
The garbage collection cycle that is referred to in the description is the interval [Tend0, TEnd1]
. With this definition the first sentence in the description becomes more meaningful.
The counter is calculated at Tend
for each garbage collection cycle. Referring to the time intervals shown below the timeline the value is the time In GC as a percentage of the total time for the entire garbage collection cycle (Not in GC and In GC).
Or more formally, at Tend1
the value of the performance counter is:
% Time in GC = 100*(Tend1 - Tstart1)/(Tend1 - Tend0)
So the counter really gives the percent time spent in GC and sampling the counter will give the value based on the previous two GC's performed.
To check this you can try to sample the counters % Time in GC as well as the three # Gen X Collections counters and see that the first counter only changes when one of the other three counters change (e.g. a GC was performed between two samples).
This counter can be used to examine if a piece of software spends a disproportionally high amount of time doing garbage collection. However, as the counter only reflects the time spent for the last garbage collection cycle you will have to sample the counter over time to properly make this examination.