Dotnet Performance Counter : Memory counters

In this article we are going to know about performance counters related to Memory and allocation during CLR processing.
As we monitor dotnet run time environment (CLR) during performance test, we need to know what to look for if we are measuring performance affected by Memory allocation , deallocation.

This is very important if we are measuring dotnet performance impact for a particular application. Before starting this, i would request readers to go through basic dotnet CLR introduction. This post might help in very basic level.



Counter related to Allocation/Size : 

Large Object Heap size (byte) : Size of large object(grater 85kb) heap which are spatially handled by GC directly(not using generational model).

Gen 0 heap size (byte): Allocatable size of Generation 0(youngest) objects.

Gen 1 heap size (byte): Allocatable size of Generation 1.

Gen 2 heap size (byte): Allocatable size for Generation 2(oldest) objects.

Number Bytes in all Heaps : Total of (Gen 1 Heap Size + Gen 2 Heap Size + Large Object Heap Size).
>This excludes generation 0 heap size as it will be collected after soonest GC collection.
>This shows current memory allocated in GC Heaps.

Note : All are updated after end of a GC collection (not allocation).
All sizes are important to analyze memory allocation amount while profiling. So, these are important counters for memory leak analysis.

Number of Total committed Bytes : Size of Virtual Memory committed by GC. In windows, initially it is inside RAM, committed, which has reserved allocated memory in page file.


Number  Total reserved Bytes : Size of Virtual Memory reserved by GC. In windows, reserved virtual memory is allocated with committed memory in page files(to disk) to support when not enough RAM space.


Committed and reserved indicate, how much resource hungry the application is. So, important counters for measuring server/run time environment capacity.



Counter related to Promotion : (Generation Upgrade) :

Finalization Survivors : Number of survived objects after a GC event due to wait to be finalized.
>Reference holding objects are not counted here
>It is not cumulative
>Updated after each GC event
>Shows count of the survivors during that particular collection only.
This is very important performance counter for the application where developers use explicit finalization of objects.This indicates extra overheads due to finalization.

Promoted Finalization-Memory from Gen 0 : Number of serviced object from generation 0 to generation 1 only due to wait to be finalized.. (partial part of Finalization Survivors )

Promoted Memory from Gen 0 (To Gen 1): Number of survived objects from Gen 0 to 1 after GC.So, this updates after each GC.

Promoted Memory from Gen 1 : (To Gen 2): Number of survived objects from Gen 1 to 2 after GC.So, this updates after each GC.

Gen 0 Promoted Bytes/Sec : It shows the rate (per second)of promotion from Gen 0 to 1.

Gen 1 Promoted Bytes/Sec : It shows the rate (per second)of promotion from Gen 1 to 2.
>This is oldest generation Nothing is promoted from generation 2 because it is the oldest generation. >Indicator of very long-lived objects promotion rat

This both promotion rates are major counters for memory leak and performance bottlenecks 

Note : Both rates measured between two collected samples.


Counters related to Deallocation/Collection:

Number of Gen 0(youngest object) Collections : This is the number of collected Generation 0 objects by GC since application started. So, it is updated after each gen 0 GC collection. This counter displays the last observed GC collection.


Number Gen 1 Collections : This is the number of collected Generation 1 objects by GC since application started. So, it is updated after each gen 1 GC collection

Number Gen 2 Collections :(Full GC that triggers all) : This is the number of collected Generation 2 objects by GC since application started. So, it is updated after each gen 2 GC collection.

Note : Higher generation GC include all lower generations so each GC generation even counter is also explicitly incremented by a higher generation (0 by1 or 2, 1 by 2) GC event.


Counters related to GC processing/Performance

Process ID : Shows monitored CLR process ID

Number if Induced GC : It shows the highest number of Explicit(manually from code) GC call. Most cases this is bad practice to control GC events as GC collect can not only clear memory, but also keeps referral objects to higher generation. So, this should one of default performance monitoring counters.
Best practice -> No need manually call GC, let CLR decide when to collect, spatially for managed code. But, sometimes , due critical resource dependencies, it is okay to call GC to cleanup non reference tails and objects.

Number of GC Handles : It shows how many GC handlers are currently working which are separate handlers from CLR and managed code. 

Number of Pinned Objects : When a GC can't move object in memory, it is pinned. This shows the number of pinned objects after latest GC event inside heaps . And, this shows pinned objects generation wise, Gen 1 pinned will be listed in Gen1 only, and so as for other generations.
This is useful counter when the application runs under low resources or at memory leak condition where memory overflown. (OOM)
 

Number of Sink Blocks in use : Counters of used synchronization blocks.
What is it? : Synchronization blocks are used to store synchronous information in per object context(  per-object data structures).
> Holds weak references to managed objects
>Scanned by GC.
Note : They can also store non sync info like COM interop metadata.

This is one of major performance counters indicating dotnet inner resource availability.

Percent (%) Time in GC : It shows a GC collection time out of last GC collection. Example , let say 5 second time interval from last GC and current GC and current GC took 2sec, so this will show 40% GC time. So, it is updated after each GC call.
This is very important counter as it shoes how much % work done by GC


Allocated Bytes/sec: It shows the rate of allocation, so it is updated after each GC collection and measured among two sample intervals.
This is an important performance counter where GC performance (or server performance) is in question. To measure, how fast the allocation happens, this helps.


Thanks .. :)