.NET Memory Management Concepts
To work with dotMemory effectively, you must have a general understanding about how .NET manages memory. The following lists summarize .NET memory concepts. For additional information, you may refer to MSDN or other materials in the Web.
Garbage Collector (GC) is the part of the .NET framework that allocates and releases memory for your .NET applications.
When a new process is started, the runtime reserves a region of address space for the process called the managed heap.
Objects are allocated in the heap contiguously one after another.
Memory allocation is a very fast process as it is just the adding of a value to a pointer.
In addition to the managed heap, an app always consumes some amount of so-called unmanaged* memory which is not managed by GC.
*Generally, it is required by .NET Common Language Runtime itself, dynamic libraries employed by the app, graphics buffer, and so on.
The process of releasing memory is called garbage collection.
When GC performs a collection, it releases only objects that are no longer in use by the application (for example, a local variable in a method can be accessed only during the method execution and after this, the variable is no longer needed).
To determine whether the object is used or not, GC examines application’s roots - strong references that are global to the application. Typically, these are global and static object pointers, local variables, and CPU registers. Learn more about possible GC roots in Analyzing GC Roots.
For each active root, GC builds a graph that contains all the objects that are reachable from these roots.
If an object is unreachable, GC considers it no longer in use and removes the object from the heap (releases the memory occupied by the object).
After the object is removed, GC compacts reachable objects in memory.
For better performance of memory release, the managed heap is divided into segments called generations: 0, 1, and 2.
When objects are just created, they are placed to the Generation 0 (Gen 0).
When Gen 0 is full (the size of the heap and generations is defined by GC), GC performs a garbage collection. During the collection, GC removes all unreachable objects from the heap. All reachable objects are promoted to the Generation 1 (Gen 1).
The Gen 0 collection is a rather quick operation.
When Gen 1 is full, the Gen 1 garbage collection is performed. All objects that survive the collection are promoted to Gen 2. The Gen 0 collection also takes place here.
When Gen 2 is full, GC performs full garbage collection. First, Gen 2 collection is performed, after this, the Gen 1 and Gen 0 collections take place. If there is still not enough memory for new allocations, GC raises the OutOfMemory exception.
During full garbage collection, GC has to pass through all objects in the heap, so, this process might have a great impact on system resources.
Large Object Heap
Due to performance reasons, large objects (>85KB) are stored in a separate segment of the managed heap called Large Object Heap (LOH).
Survived objects in LOH are not compacted*. This means that LOH becomes fragmented over time.
*Starting from .NET Framework 4.5.1, you can force GC to compact LOH during the full garbage collection.