Friday, February 20, 2009

Understanding memory management in mixed mode applications (Managed and Unmanaged).


All developers are familiar with the GC class and .NET and its important role in memory management. It was designed to take out the burden of allocating and releasing memory to hold objects. This is a great feature though it comes at a price; you are not in control of when memory is released. This is not an issue for most applications and most objects. The problems start when you allocate large objects.

In the references I include references to information about what is going internally in CLR but here goes a summary:

The .NET garbage collector is a generational collector. It has three generations: generation 0, generation 1, and generation 2. Generations are the logical view of the garbage collector heap.

Objects live on managed heap segments that are chunks of memory that the garbage collector reserves from the OS by calling VirtualAlloc. Large objects have more that 85kb and belong to generation 2, and are collected only in generation 2.

The collection of an older generation triggers the collection of the younger ones. When a generation 1 garbage collection happens, both generation 1 and 0 are collected.

A garbage collection occurs if one of the following conditions happens:

1. Allocation Exceeds the Generation 0 or Large Object Threshold. Most GCs happen because of allocations on the managed heap (this is the most typical case).

2. System.GC.Collect Is called.

3. System Is in Low Memory Situation. The high memory notification is sent by the OS.

The threshold is a property of each generation. Allocating objects into a generation gets the amount of memory used closer to the generation's threshold. If the threshold is exceeded a garbage collection is triggered on that generation.

The CLR clears the memory for every new object. Imagining it takes two cycles to clear 1 byte, it means it takes closely 170,000 cycles to clear the smallest large object (85kb).

When an application makes both managed and unmanaged memory allocations it is a good practice to tell the GC how much memory is being allocated by the unmanaged threads. This is done using the AddMemoryPressure API. This call will not trigger GC by itself but it will allow the GC to tune memory management.