Memory<T> and Span<T>
1. The Core Problem They Solve
In traditional C#, slicing an array or string (e.g., getting a sub-section) requires creating a new copy of the data on the heap. This leads to temporary memory allocations that put significant pressure on the garbage collector (GC), causing performance overhead and potential "stop-the-world" pauses in high-throughput applications.
2. Span<T>: The "View" on the Stack
What it is: A
ref structthat represents a contiguous block of memory. Think of it as a lightweight, zero-allocation "view" or a slice.Key Characteristics:
Stack-only: It cannot be a field in a class, used in an
asyncmethod, or stored on the heap. This safety constraint prevents dangling pointers.Zero-Allocation: Creating a
Span<T>from an existing array or buffer is a stack operation that doesn't allocate any new heap memory.High Performance: It provides direct, bounds-checked access to the underlying memory, making it ideal for synchronous, performance-critical operations.
Use Case: Use
Span<T>for short-lived, high-performance tasks within a single method.
3. Memory<T>: The Managed Buffer on the Heap
What it is: A managed struct that also represents a contiguous memory block.
Key Characteristics:
Managed and Heap-Friendly: Unlike
Span<T>,Memory<T>can be stored on the heap as a field in a class, passed between methods, and used acrossawaitboundaries in asynchronous code.Safe Reference: It provides a safe way to hold a long-lived reference to a memory buffer.
Span<T>Producer: You access the underlying memory by getting aSpan<T>from it (myMemory.Span).
Use Case: Use
Memory<T>when you need a persistent reference to a buffer that needs to be passed around or used in asynchronous operations.
4. The Memory<T> & Span<T> Relationship
Producer-Consumer Model:
Memory<T>is the producer of a long-lived, managed memory buffer.Span<T>is the consumer that provides a temporary, high-performance "view" of that buffer for specific operations.Unified API: They provide a consistent way to work with different memory sources—arrays, strings, and unmanaged memory—without needing to copy data.
5. Key Performance Takeaway: Reduced GC Pressure
The primary benefit is avoiding temporary heap allocations. Instead of creating a new byte[] for every segment of data you need to process, you allocate a single, larger buffer once. All subsequent slicing operations using Span<T> are stack-allocated and allocation-free, which means the GC doesn't need to track or collect a multitude of small, temporary objects. This leads to more consistent performance, fewer unpredictable pauses, and overall more efficient code.