C# > Interop and Unsafe Code > Unsafe Code > Fixed Keyword

Using the 'fixed' keyword to pin memory for direct access

This snippet demonstrates how to use the fixed keyword in C# to pin an array in memory, allowing for direct pointer manipulation via unsafe code. This is crucial when interacting with unmanaged resources or optimizing performance-critical sections where direct memory access is required.

Code Example: Pinning an array

This code snippet initializes an integer array. The fixed statement then 'pins' the array's first element in memory. This prevents the garbage collector from moving the array while the fixed block is executing. Inside the fixed block, a pointer ptr is created, pointing to the first element of the array. This pointer allows us to directly read and modify the array's contents using pointer arithmetic. After the fixed block completes, the array is unpinned, and the garbage collector is free to move it again. Note that modifications made within the fixed block are reflected in the original array.

using System;

public unsafe class FixedExample
{
    public static void Main(string[] args)
    {
        int[] arr = { 10, 20, 30, 40, 50 };

        fixed (int* ptr = &arr[0])
        {
            Console.WriteLine("Original value at index 2: " + arr[2]);
            // Directly modify the value at index 2 using the pointer
            ptr[2] = 100;
            Console.WriteLine("Modified value at index 2: " + arr[2]);
        }

        // The array is now unpinned and can be moved by the GC again.
        Console.WriteLine("Value at index 2 after 'fixed' block: " + arr[2]);
    }
}

Concepts Behind the Snippet

The fixed keyword is essential for working with unmanaged resources or optimizing performance-critical sections in C#. It ensures that a managed variable (typically an array or string) remains at a fixed memory location during the execution of a block of code. This is necessary because the garbage collector can move objects in memory to reduce fragmentation, which would invalidate any pointers to those objects. The fixed keyword essentially tells the garbage collector to 'hold off' on moving the object for the duration of the fixed block.

Real-Life Use Case

A common use case for the fixed keyword is when interacting with native libraries (e.g., through P/Invoke). Native libraries often expect pointers to memory buffers. The fixed keyword allows you to pass managed arrays or strings to these libraries without the risk of the garbage collector moving the data during the native call. Another use case is in high-performance scenarios where you need to directly manipulate memory to avoid the overhead of managed access.

Best Practices

  • Minimize the Scope: Keep the fixed block as small as possible. The longer an object is pinned, the longer the garbage collector is prevented from performing its work, which can impact performance.
  • Avoid Long-Lived Pointers: Do not store pointers obtained within a fixed block for later use outside the block. The pointer becomes invalid once the fixed block exits, as the garbage collector is then free to move the object.
  • Error Handling: Be mindful of exceptions within the fixed block. Ensure proper cleanup to prevent memory corruption or resource leaks.

Interview Tip

Be prepared to explain why the fixed keyword is necessary and how it interacts with the garbage collector. Understanding the trade-offs between performance gains and potential garbage collection overhead is crucial. Also, be prepared to discuss scenarios where using fixed is appropriate versus alternative approaches.

When to use them

Use the fixed keyword when:

  • Interacting with unmanaged code that requires pointers to managed data.
  • Optimizing performance-critical sections of code that involve direct memory manipulation.
  • Working with hardware devices that require specific memory addresses.

Memory footprint

The fixed keyword itself doesn't directly increase the memory footprint. However, excessive use of fixed can indirectly impact memory management because it prevents the garbage collector from compacting memory. This can lead to increased memory fragmentation and potentially higher overall memory usage.

Alternatives

  • Marshal.Copy: If you need to pass data to unmanaged code but don't require direct pointer access, consider using Marshal.Copy to copy the data to an unmanaged buffer.
  • Span: In newer versions of C#, Span provides a safer and more efficient way to work with contiguous regions of memory without requiring unsafe code or the fixed keyword in many scenarios.

Pros

  • Direct Memory Access: Allows for direct manipulation of memory, which can be essential for performance-critical tasks.
  • Interop with Unmanaged Code: Enables seamless interaction with native libraries that expect pointers to managed data.

Cons

  • Requires Unsafe Code: The fixed keyword necessitates the use of unsafe code, which bypasses some of the safety features of C#.
  • Garbage Collection Overhead: Pinning objects for extended periods can hinder the garbage collector's ability to compact memory, potentially leading to performance issues.
  • Potential for Memory Corruption: Incorrect pointer manipulation within a fixed block can lead to memory corruption and application crashes.

FAQ

  • What happens if I try to access the pinned array outside the 'fixed' block using the pointer?

    Accessing the pinned array using the pointer outside the fixed block is undefined behavior. The garbage collector is free to move the array once the fixed block exits, invalidating the pointer. Attempting to dereference the pointer could lead to memory corruption or application crashes.
  • Can I use the 'fixed' keyword with strings?

    Yes, you can use the fixed keyword with strings. However, strings are immutable in C#, so you can only use a fixed string pointer for reading the string's contents, not for modifying them directly. Modifying a string through a fixed pointer is extremely dangerous and can lead to unpredictable behavior.