Not every allocation needs to touch the heap. For small, short-lived buffers, C# offers stackalloc — a way to allocate memory directly on the stack. Stack allocations are effectively free: they cost nothing to allocate and nothing to collect, because they vanish the moment the method returns.

Basic Usage

stackalloc creates a block of memory on the current stack frame. Since C# 7.2, you can assign the result to a Span<T>, keeping the code safe and bounds-checked:

Example.cs
Span<byte> buffer = stackalloc byte[256];
buffer[0] = 0xFF;
buffer[255] = 0x01;
// buffer is automatically reclaimed when the method exits

No new, no GC involvement, no finaliser. The memory lives on the stack and disappears with the frame.

A Practical Example: Formatting Numbers

Suppose you need to format an integer as a hex string. A heap-based approach allocates a temporary char[]:

Example.cs
// Heap allocation
public string ToHexHeap(int value)
{
    char[] chars = new char[8];
    value.TryFormat(chars, out int written, "X8");
    return new string(chars, 0, written);
}

With stackalloc, the intermediate buffer costs nothing:

Example.cs
// Stack allocation
public string ToHexStack(int value)
{
    Span<char> chars = stackalloc char[8];
    value.TryFormat(chars, out int written, "X8");
    return new string(chars[..written]);
}

The final new string(...) still allocates on the heap — you cannot avoid that if you need to return a string. But the temporary working buffer is free.

When to Use stackalloc

The stack in .NET is typically 1 MB on 64-bit systems (configurable per thread, but not commonly changed). Allocating too much will cause a StackOverflowException, which is fatal and uncatchable.

A safe rule of thumb: keep stackalloc under 512 bytes. For anything larger, fall back to ArrayPool<T>:

Example.cs
public void ProcessData(int size)
{
    Span<byte> buffer = size <= 512
        ? stackalloc byte[size]
        : new byte[size]; // or rent from ArrayPool

    FillBuffer(buffer);
    ConsumeBuffer(buffer);
}

This hybrid pattern is used extensively in the .NET runtime itself. Methods like Encoding.GetString, Guid.ToString, and IPAddress.TryFormat all use stackalloc for small buffers and fall back to heap allocation for larger ones.

stackalloc in Expressions (C# 8+)

Since C# 8, stackalloc can appear in expressions, not just in declarations. This enables using it inline:

Example.cs
ReadOnlySpan<int> primes = stackalloc[] { 2, 3, 5, 7, 11, 13 };

if (primes.Contains(value))
{
    Console.WriteLine("Prime!");
}

This is particularly useful for small lookup tables that would otherwise require a heap-allocated array. The ReadOnlySpan<int> here is stack-allocated and the JIT may even optimise the Contains call into a series of comparisons.

Restrictions

stackalloc has several constraints:

Combining with Unsafe Code

In rare cases, you may see stackalloc used with pointers in unsafe contexts. This is the older syntax and lacks bounds checking:

Example.cs
unsafe
{
    byte* buffer = stackalloc byte[256];
    buffer[0] = 0xFF;
    // No bounds checking — buffer[300] would corrupt the stack
}

Prefer the Span<T> form in all modern code. It provides the same performance with full safety.

Summary

stackalloc is a precision tool for eliminating small, temporary allocations from hot paths. It works best for buffers under 512 bytes in synchronous methods. Combined with Span<T>, it provides zero-cost allocation with full memory safety. When you see allocation pressure from short-lived small arrays in a profiler, stackalloc is often the simplest fix.