Garbage collection, generations and the large object heap


The .Net CLR maintains a managed heap used to dynamically allocate and garbage collect objects. This heap is divided into two address spaces – one used by a generational garbage collector for small objects and a second used for large objects.

The three generations

The first address space (sometimes called the small object heap – SOH) holds the three GC generations (0, 1 and 2) and is used for small objects (less than 85,000 bytes in size.) Each generation has a memory budget which can change over the lifetime of the application and is used to trigger collection of that generation.

The garbage collector will collect objects in generation 0 when its memory budget is exceeded. Any survivors of a GC on generation 0 are promoted to generation 1 (any non-survivors have their memory reclaimed.) Each generation is a contiguous address space – so promotion to generation 1 includes moving the objects into the address space allocated to generation 1 – compacting the memory used.

The GC will continue collecting generation 0 until the memory budget for generation 1 also gets exceeded. Once this occurs both generation 0 and generation 1 are collected. Any survivors of the generation 1 collection are promoted to generation 2. Generation 2 contains the oldest / longest lived objects. Again promotion includes compacting the memory by moving the objects into the address space allocated for generation 2.

This process continues with frequent collections of generation 0, less frequent collections of generation 1 and infrequent collections of generation 2. As the garbage collector performs each collection it also adapts to the memory usage patterns of the application – changing the memory budget allocations for each generation to optimise performance.

The large object heap

The second address space contains the large object heap (LOH) and is used for large objects (85,000 bytes and larger.)

Objects on the LOH are considered part of generation 2 and collected with this generation. This means that short-lived large objects will only be collected either when the generational GC collects generation 2, the LOH exceeds its memory budget or the user programmatically invokes a collection of generation 2.

Due to the cost of moving large objects, the CLR does not compact the memory space for the LOH. Large objects will remain where they were originally allocated. This is an implementation artefact of the CLR GC – as such it may be changed in the future. The size boundary of objects considered large may also change so if you require a static memory location for an object you will need to pin it.