✅What Is Span?
Span is a ref struct that enables you to efficiently and safely manipulate a contiguous region of memory (arrays, strings, native memory) without allocating any additional memory.
❓ Why do we need Span?
- Avoid unnecessary memory allocations.
- Work with a portion of an array or a string without copying.
- Manipulate buffers or memory segments efficiently.
- Access stack memory via stackalloc for performance gains.
Declaring and Using Span
- From an existing array or string
// Given an array
int[] numbers = { 10, 20, 30, 40, 50 };
// Create a Span<T> over the whole array
Span<int> allNums = numbers.AsSpan();
// Create a slice over elements 1–3 (20,30,40)
Span<int> middleNums = allNums.Slice(1, 3);
// You can read and write through the span:
middleNums[0] = 25; // numbers[1] is now 25
Console.WriteLine(numbers[2]); // prints 30
// For strings use ReadOnlySpan<char>
string text = "Hello, world!";
ReadOnlySpan<char> hello = text.AsSpan(0, 5);
Console.WriteLine(hello.ToString()); // "Hello"
- On the stack with stackalloc
// Allocate 8 ints on the stack (no heap allocation)
Span<int> stackBuf = stackalloc int[8];
// Initialize and use
for (int i = 0; i < stackBuf.Length; i++)
{
stackBuf[i] = i * i;
}
Console.WriteLine(stackBuf[3]); // prints 9
❓ Why do we need stackalloc?
Since Span is a ref struct and lives on the stack, why do we need stackalloc to allocate a buffer on the stack?
✅ Yes, Span itself lives on the stack (because it’s a ref struct)
❌ But the data it points to is not automatically on the stack
🔍 By default:
Span<byte> s = new byte[100];
➡️ Here:
- The Span instance lives on the stack
- But the actual byte[100] array is allocated on the heap
- That allocation is managed by the garbage collector (GC)
✅ With stackalloc:
Span<byte> s = stackalloc byte[100];
➡️ Now:
- Both the Span and the 100 bytes of data are on the stack
- 🧠 No heap allocation, and therefore no GC pressure
Code | Where is Span<T> ? |
Where is the data? | GC involved? |
---|---|---|---|
Span<byte> s = new byte[100]; |
📦 Stack | 🧠 Heap | ✅ Yes |
Span<byte> s = stackalloc byte[100]; |
📦 Stack | 📦 Stack | ❌ No |
⛔ Limitations of Span
💥 Why can't Span be a field in a class?
- Class instances live on the heap.
- Span is a ref struct, which means it must live on the stack and is not allowed to be stored on the heap.
- If a Span were stored in a class field, it could keep referencing stack memory that is no longer valid once the method exits.
- This would lead to undefined behavior, potential memory corruption, and security risks.
💥Why is Span not allowed in yield return,async methods or lambdas?
- yield return, async and lambda expressions are also compiled into state machines that live on the heap.
- Variables from inside the async/lambda context are often captured and stored on the heap as part of the closure or state machine.
- If a Span were captured this way, it would leak a reference to stack memory into a heap object.
❌ This violates memory safety and lifetime guarantees, so the compiler blocks this usage.
Top comments (0)