DEV Community

Cover image for Span<T> en C#
Habib BARAKET
Habib BARAKET

Posted on

Span<T> en C#

Span

✅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?

  1. Avoid unnecessary memory allocations.
  2. Work with a portion of an array or a string without copying.
  3. Manipulate buffers or memory segments efficiently.
  4. Access stack memory via stackalloc for performance gains.

Declaring and Using Span

  1. 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"

Enter fullscreen mode Exit fullscreen mode
  1. 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

Enter fullscreen mode Exit fullscreen mode

❓ 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)