Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The stackalloc operator allocates a contiguous block of memory on the execution stack rather than the managed heap. Because the memory is allocated on the stack, it is not subject to garbage collection (GC) and is automatically reclaimed when the method in which it was allocated returns.

Syntax and Return Types

The operator can be assigned to two different types, which dictates whether the execution context must be marked as unsafe. 1. Safe Context (Span<T> / ReadOnlySpan<T>) Introduced in C# 7.2, stackalloc can be assigned to a Span<T> or ReadOnlySpan<T> without requiring the unsafe keyword or compiler flag. This provides memory safety bounds checking.
Span<int> safeBuffer = stackalloc int[10];
ReadOnlySpan<byte> safeReadOnlyBuffer = stackalloc byte[256];
2. Unsafe Context (Pointers) Historically, stackalloc was strictly an unsafe operation that returned a pointer to the first element of the allocated block. This requires the unsafe context.
unsafe
{
    int* unsafeBuffer = stackalloc int[10];
}

Initialization

You can initialize the memory block at the time of allocation using collection initializer syntax. When an initializer is provided, the length can be inferred.
// Explicit length and type
Span<int> explicitInit = stackalloc int[3] { 10, 20, 30 };

// Inferred length
Span<int> inferredLength = stackalloc int[] { 10, 20, 30 };

// Inferred length and type
Span<int> fullyInferred = stackalloc[] { 10, 20, 30 };

Technical Constraints and Rules

  • Type Restrictions: The type T in stackalloc T[length] must be an unmanaged type. This includes primitive types (like int, float, byte), enum types, pointers, or user-defined struct types that contain only unmanaged fields. You cannot use stackalloc with reference types or structs containing reference types.
  • Memory Limits: The execution stack has a fixed, limited size (typically 1 MB to 4 MB depending on the OS and environment). Allocating a block larger than the available stack space will result in a non-catchable StackOverflowException, terminating the process.
  • Zero-Initialization: By default, all memory allocated via stackalloc (whether assigned to a pointer or a Span<T>) is zero-initialized. The C# compiler enforces this by emitting the initlocals flag on the method, which causes the localloc IL instruction to zero out the memory. However, if the [System.Runtime.CompilerServices.SkipLocalsInit] attribute is applied to the method or module, the compiler omits the initlocals flag. In this scenario, both pointer and Span<T> allocations are left uninitialized and will contain garbage data.
  • Contextual Restrictions:
    • stackalloc cannot be used inside catch or finally blocks.
    • Async and Iterator Methods: Since C# 8.0, stackalloc is permitted in async methods and iterator methods (yield) provided the result is assigned to a Span<T> or ReadOnlySpan<T>. However, the resulting span cannot be used across await or yield boundaries, as the stack frame is suspended and the memory would become invalid. Assigning stackalloc to a pointer type remains strictly prohibited in async and iterator methods.
  • Expression Usage: When assigned to a Span<T>, stackalloc is a valid expression and can be used inline within other operations, such as method arguments or conditional expressions.
// Inline expression usage
void ProcessData(Span<byte> data) { /* ... */ }

ProcessData(stackalloc byte[] { 0x01, 0x02, 0x03 });

// Conditional allocation
int length = 5;
Span<int> buffer = length <= 128 ? stackalloc int[length] : new int[length];
Master C# with Deep Grasping Methodology!Learn More