High Performance with `Span<T>`
High Performance with Span<T>
Span<T> is a stack-allocated representation of contiguous memory. it enables type-safe and memory-safe access to any memory, whether itβs on the managed heap, the stack, or native memory.
Why use Span?
It allows you to slice arrays or strings without allocating new objects on the heap, significantly reducing GC pressure.
Example: Parsing Data
In this example, we use line highlighting (the 5 syntax) to focus on the slicing logic.
public void ParseData(ReadOnlySpan<char> data) {
// Slice without allocation!
var firstPart = data.Slice(0, 5);
if (firstPart.Equals("HELLO", StringComparison.Ordinal)) {
var remaining = data.Slice(5);
Console.WriteLine($"Found: {remaining.ToString()}");
}
}π Reducing Allocations with ArrayPool<T>
ArrayPool<T> provides a high-performance pool of reusable arrays, which drastically reduces the overhead of creating and garbage collecting short-lived arrays.
using System.Buffers;
var pool = ArrayPool<byte>.Shared;
byte[] buffer = pool.Rent(1024); // Rent an array of at least 1024 bytes
try {
// Use the buffer...
} finally {
pool.Return(buffer); // Always return to the pool!
}π οΈ Advanced Interop with MemoryMarshal
MemoryMarshal provides low-level, zero-copy methods for casting memory between different types.
using System.Runtime.InteropServices;
ReadOnlySpan<byte> bytes = stackalloc byte[] { 0x01, 0x00, 0x00, 0x00 };
// Zero-copy cast from bytes to a single int!
int value = MemoryMarshal.Read<int>(bytes); π‘ Performance Tip: stackalloc
For very small, temporary buffers, use stackalloc within a Span<T> to allocate memory on the stack instead of the heap.
Span<int> numbers = stackalloc int[16];