Course contentsShow
← C#
Lesson 1737 of 1,90816. Performance and DiagnosticsFree lesson

Understanding Pinned Objects and Heap Fragmentation

Learners will safely manage fixed memory pointers while mitigating the impact on GC heap compaction.

In this lesson, you will learn how to use the fixed statement to interact with unmanaged memory while minimizing the negative impact on the Garbage Collector’s (GC) ability to defragment the heap.

The Cost of Stability

The .NET Garbage Collector is highly efficient because it compacts the heap; it moves objects around to eliminate gaps, keeping free memory contiguous. However, when you perform interop operations—such as passing a buffer to a C++ library—the underlying API expects the memory address to remain constant. To satisfy this, we use pinning, which tells the GC: "Do not move this object."

While necessary, pinning is a performance tax. If you pin an object, the GC cannot move it to close gaps in the heap. If you pin many objects, you create "islands" in memory that force the GC to work around them, leading to heap fragmentation. This fragmentation increases the cost of future allocations and can lead to OutOfMemoryException errors even when total free memory seems sufficient.

Best Practices for Pinning

To mitigate fragmentation, follow these rules:

  1. Pin for the Shortest Possible Time: Only keep an object pinned for the duration of the unmanaged call.
  2. Prefer Stack Allocation: If you need a temporary buffer, use stackalloc instead of pinning a managed array. Stack memory is not managed by the GC and does not cause heap fragmentation.

Consider this example of safe, localized pinning:

public unsafe void ProcessData(byte[] data)
{
    // Pin only for the duration of the scope
    fixed (byte* p = data)
    {
        // Call unmanaged API here
        NativeLibrary.Process(p, data.Length);
    } 
    // Once we exit the block, the object is immediately unpinned
}

By keeping the fixed block narrow, you ensure the object is only ineligible for relocation for a few microseconds. Avoid long-lived pinning, such as pinning objects in a class field, as this creates a permanent "hole" in the heap that the GC can never fill.

Key Takeaway: Pinning prevents the GC from compacting memory; keep fixed blocks as short as possible and use stackalloc whenever you can to avoid pinning managed heap objects entirely.