Performance Monitoring – Garbage Collection

I see this topic quite a bit on newsgroups and in microsoft chats.
People ask how and what to monitor to check out the performance of
their application. First and foremost, I tell people to get CLRProfiler.

The CLR Profiler includes a number of very useful
views of the allocation profile, including a histogram of allocated
types, allocation and call graphs, a time line showing GCs of various
generations and the resulting state of the managed heap after those
collections, and a call tree showing per-method allocations and
assembly loads.

This is an invaluable tool.

This blog post topic isn’t about the CLRProfiler though. This is about
using PerfMon. When installing .Net, many, many new counters are added
that allow you to get detailed and real-time information about the
performance of your applications.  We are only going to talk about
one set of those for monitoring garbage collections.  Launch
PerfMon, and click the + to add new counters. In the Performance
Object, select “.Net CLR Memory”. It should look something similar to
below:

Select a specific application to monitor from the right. You see on my
machine the managed applications that are running. I can select OMEA
Reader and profile its memory and GC usage.

I always use the following when doing checking the performance of the GC, along with their explanations:

# Gen 0 Collections – This counter displays the number of times
the generation 0 objects (youngest; most recently allocated) are
garbage collected (Gen 0 GC) since the start of the application. Gen 0
GC occurs when the available memory in generation 0 is not sufficient
to satisfy an allocation request. This counter is incremented at the
end of a Gen 0 GC. Higher generation GCs include all lower generation
GCs. This counter is explicitly incremented when a higher generation
(Gen 1 or Gen 2) GC occurs. _Global_ counter value is not accurate and
should be ignored. This counter displays the last observed value.

Gen 0 Heap Size – This counter displays the maximum bytes that
can be allocated in generation 0 (Gen 0); its does not indicate the
current number of bytes allocated in Gen 0. A Gen 0 GC is triggered
when the allocations since the last GC exceed this size. The Gen 0 size
is tuned by the Garbage Collector and can change during the execution
of the application. At the end of a Gen 0 collection the size of the
Gen 0 heap is infact 0 bytes; this counter displays the size (in bytes)
of allocations that would trigger the next Gen 0 GC. This counter is
updated at the end of a GC; its not updated on every allocation.

# Gen 1 Collections – This counter displays the number of times
the generation 1 objects are garbage collected since the start of the
application. The counter is incremented at the end of a Gen 1 GC.
Higher generation GCs include all lower generation GCs. This counter is
explicitly incremented when a higher generation (Gen 2) GC occurs.
_Global_ counter value is not accurate and should be ignored. This
counter displays the last observed value.

Gen 1 heap size – This counter displays the current number of
bytes in generation 1 (Gen 1); this counter does not display the
maximum size of Gen 1. Objects are not directly allocated in this
generation; they are promoted from previous Gen 0 GCs. This counter is
updated at the end of a GC; its not updated on every allocation.

# Gen 2 Collections – This counter displays the number of times
the generation 2 objects (older) are garbage collected since the start
of the application. The counter is incremented at the end of a Gen 2 GC
(also called full GC). _Global_ counter value is not accurate and
should be ignored. This counter displays the last observed value.

Gen 2 heap size – This counter displays the current number of
bytes in generation 2 (Gen 2). Objects are not directly allocated in
this generation; they are promoted from Gen 1 during previous Gen 1
GCs. This counter is updated at the end of a GC; its not updated on
every allocation.

Large Object Heap Size – This counter displays the current size
of the Large Object Heap in bytes. Objects greater than 20 KBytes are
treated as large objects by the Garbage Collector and are directly
allocated in a special heap; they are not promoted through the
generations. This counter is updated at the end of a GC; its not
updated on every allocation.

# Bytes in all Heaps – This counter is the sum of four other
counters; Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the
Large Object Heap Size. This counter indicates the current memory
allocated in bytes on the GC Heaps.

Promoted memory from Gen 0 – This counter displays the bytes of
memory that survive garbage collection (GC) and are promoted from
generation 0 to generation 1; objects that are promoted just because
they are waiting to be finalized are not included in this counter. This
counter displays the value observed at the end of the last GC; its not
a cumulative counter.

Promoted memorty from Gen 1 – This counter displays the bytes of
memory that survive garbage collection (GC) and are promoted from
generation 1 to generation 2; objects that are promoted just because
they are waiting to be finalized are not included in this counter. This
counter displays the value observed at the end of the last GC; its not
a cumulative counter. This counter is reset to 0 if the last GC was a
Gen 0 GC only.

So I added all of these counters, and opened up OMEA Reader. I
started up the PerfMon to start tracking and then did an update for all
my webfeeds in OMEA Reader. As soon as that completed, I waited about 5
seconds and then took this snapshot of the report view of my
performance monitor:

About a year ago, I spoke with a GC architect and he informed me
that a very optimal ratio for generational GC’s is 100-10-1 (gen
0-1-2). The app I’m profiling, under the circumstances and with
resources available, doesn’t reach that optimal level, but I’ve never
profiled anything that does. This GC collection ratio is what you are
primarily looking for from these counters. GC’s are expensive and you’d
like to see them kept at a minimum. You won’t see a counter for LOH
(large object heap) collections. They happen every time a Gen 2
collection occurs, so the collection counts are the same for both.

This entry was posted in .Net Development, Most Popular. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

2 Responses to Performance Monitoring – Garbage Collection

  1. rlewallen says:

    Rolo, the garbage collector promotes objects to other generations automatically.

  2. rolo says:

    how change garbage collection levels?
    where?

Leave a Reply