Unlocking Hidden .NET Speed: How to Use Span Like a Pro

Enhancing Performance with Span in C#

Ever felt like your application is doing more work than necessary just to move a few bytes around? You might be missing out on one of C#’s most powerful performance tools: Span<T>. Let me show you how this little slice of memory magic can shave milliseconds off your hot paths.

What Is Span?

Span<T> is a value type introduced in C# 7.2 that represents a contiguous region of arbitrary memory. It’s like a super-efficient array wrapper that doesn’t allocate on the heap.

Unlike arrays or lists, Span<T> is stack-allocated and provides a safe, fast way to work with slices of data—whether that’s arrays, strings, or unmanaged memory.

Key characteristics:

  • No heap allocations
  • Fast slicing and slicing operations
  • Type-safe and memory-safe
  • Works with stackalloc for high-performance scenarios

The Performance Boost: Why Use Span?

Let’s be blunt: allocations are expensive. Every time you create a new array or list, you add pressure on the garbage collector.

With Span<T>, you:

  • Avoid allocations for temporary data structures
  • Work directly with memory for tasks like parsing, encoding, and transformations
  • Minimize copying of data

Here’s a microbenchmark scenario:

string input = "1234567890";
ReadOnlySpan<char> span = input;
ReadOnlySpan<char> sliced = span.Slice(2, 5);
Console.WriteLine(sliced.ToString()); // Output: 34567

No new string is created—you’re working on the same memory.

Getting Started: Syntax & Basic Usage

Span<int> numbers = stackalloc int[5] { 1, 2, 3, 4, 5 };
Span<int> slice = numbers.Slice(1, 3);

foreach (var number in slice)
    Console.WriteLine(number);

Explanation:

  • stackalloc allocates memory on the stack (not heap!)
  • Slice(1, 3) returns elements 2, 3, and 4
  • No garbage collector involvement

Want to operate on parts of a byte array?

byte[] buffer = new byte[100];
Span<byte> bufferSpan = buffer.AsSpan(10, 50);

Advanced Examples & Use Cases

Parsing integers from a large file buffer:

ReadOnlySpan<byte> line = Encoding.UTF8.GetBytes("42,65,89,100");
int sum = 0;
foreach (var part in line.ToString().Split(','))
    sum += int.Parse(part);
Console.WriteLine(sum);

Better yet:

ReadOnlySpan<byte> line = Encoding.UTF8.GetBytes("42,65,89,100");
ReadOnlySpan<char> span = Encoding.UTF8.GetString(line).AsSpan();
int sum = 0;
int comma;
do
{
    comma = span.IndexOf(',');
    var segment = comma != -1 ? span.Slice(0, comma) : span;
    sum += int.Parse(segment);
    span = comma != -1 ? span.Slice(comma + 1) : Span<char>.Empty;
} while (!span.IsEmpty);

Console.WriteLine(sum);

Avoids allocations by skipping string.Split.

Unsafe interop/memory manipulation:

unsafe
{
    int* ptr = stackalloc int[3] { 1, 2, 3 };
    Span<int> span = new Span<int>(ptr, 3);
    span[0] = 10;
    Console.WriteLine(span[0]); // Output: 10
}

Best Practices for Using Span

  • Use Span<T> when you need high-performance, temporary views over data
  • Combine with stackalloc for max performance
  • Use ReadOnlySpan<T> when you don’t need to modify data
  • Ideal for parsers, encoders, formatters, protocol readers
  • Use in performance-critical hot paths to reduce allocations

Common Pitfalls & Limitations

  • Can’t be stored in fields of classes (unless in ref structs)
  • Can’t be boxed or used with async methods
  • Short-lived: only live as long as the stack frame
  • Misusing Span<T> can cause undefined behavior or exceptions

FAQ: Common Span Questions

Can I use Span in async methods?

No. Spans can’t be captured across await. Use memory pooling or arrays instead.

How do I return a Span from a method?

You can’t unless it’s returned immediately from a ref struct or within the same stack frame.

What’s the difference between Span and Memory?

Span<T> is stack-only and fast; Memory<T> is heap-safe and can be used in async methods.

Conclusion: Span is Small but Mighty

If you’re chasing those last drops of performance or want to avoid heap allocations without resorting to unsafe code, Span<T> is your friend. I’ve used it in data pipelines, serializers, and even to shave off GC pressure in tight loops. It’s one of those underused gems in C#.

Give it a try—your performance metrics will thank you.

What’s the most clever way you’ve used Span<T> in your code? Share it in the comments below!

Leave a Reply

Your email address will not be published. Required fields are marked *