Phase 24 of 30 · Topic 24.2

Large Object Heap (LOH) & Pinned Object Heap (POH)

1Concept

Objects >= 85,000 bytes allocate directly on the Large Object Heap (LOH), which is not compacted by default. The Pinned Object Heap (POH in .NET 5+) stores pinned interop buffers without fragmenting the generational heap.

2Architecture Diagram

Managed Heap Segments:
├── Small Object Heap (SOH) ──> Gen 0, Gen 1, Gen 2 (Compacted on GC)
├── Large Object Heap (LOH) ──> Objects >= 85,000 bytes (Swept, rare compaction)
└── Pinned Object Heap (POH)──> Native pinned buffers (Zero heap compaction fragmentation!)

3Code Example

C# 13 & .NET 9
using System;

public class LohAndPohDemo
{
    public static void Main()
    {
        // Allocates directly on Large Object Heap (>= 85,000 bytes)
        byte[] largeArray = new byte[90_000];
        Console.WriteLine($"Large Array Generation: Gen {GC.GetGeneration(largeArray)} (LOH is part of Gen 2)");

        // Allocate on Pinned Object Heap (.NET 6+)
        byte[] pinnedBuffer = GC.AllocateArray<byte>(1024, pinned: true);
        Console.WriteLine($"Pinned Array allocated directly on POH: {GC.GetGeneration(pinnedBuffer)}");
    }
}

4Expected Output

Large Array Generation: Gen 2 (LOH is part of Gen 2)
Pinned Array allocated directly on POH: 2

5Key Takeaways

  • Avoid frequent short-lived LOH allocations (>85KB); use `ArrayPool<T>` instead.
  • POH eliminates memory fragmentation caused by `fixed` pointers during socket I/O.
  • Configure `GCSettings.LargeObjectHeapCompactionMode` if LOH defragmentation is needed.