Редагувати

Поділитися через


stackalloc expression (C# reference)

A stackalloc expression allocates a block of memory on the stack. A stack-allocated memory block created during the method execution is automatically discarded when that method returns. You can't explicitly free the memory allocated with stackalloc. A stack allocated memory block isn't subject to garbage collection and doesn't have to be pinned with a fixed statement.

You can assign the result of a stackalloc expression to a variable of one of the following types:

  • System.Span<T> or System.ReadOnlySpan<T>, as the following example shows:

    int length = 3;
    Span<int> numbers = stackalloc int[length];
    for (var i = 0; i < length; i++)
    {
        numbers[i] = i;
    }
    

    You don't have to use an unsafe context when you assign a stack allocated memory block to a Span<T> or ReadOnlySpan<T> variable.

    When you work with those types, you can use a stackalloc expression in conditional or assignment expressions, as the following example shows:

    int length = 1000;
    Span<byte> buffer = length <= 1024 ? stackalloc byte[length] : new byte[length];
    

    You can use a stackalloc expression or a collection expression inside other expressions whenever a Span<T> or ReadOnlySpan<T> variable is allowed, as the following example shows:

    Span<int> numbers = stackalloc[] { 1, 2, 3, 4, 5, 6 };
    var ind = numbers.IndexOfAny(stackalloc[] { 2, 4, 6, 8 });
    Console.WriteLine(ind);  // output: 1
    
    Span<int> numbers2 = [1, 2, 3, 4, 5, 6];
    var ind2 = numbers2.IndexOfAny([2, 4, 6, 8]);
    Console.WriteLine(ind2);  // output: 1
    

    Note

    We recommend using Span<T> or ReadOnlySpan<T> types to work with stack allocated memory whenever possible.

  • A pointer type, as the following example shows:

    unsafe
    {
        int length = 3;
        int* numbers = stackalloc int[length];
        for (var i = 0; i < length; i++)
        {
            numbers[i] = i;
        }
    }
    

    As the preceding example shows, you must use an unsafe context when you work with pointer types.

    In the case of pointer types, you can use a stackalloc expression only in a local variable declaration to initialize the variable.

The amount of memory available on the stack is limited. If you allocate too much memory on the stack, a StackOverflowException is thrown. To avoid that, follow the rules below:

  • Limit the amount of memory you allocate with stackalloc. For example, if the intended buffer size is below a certain limit, you allocate the memory on the stack; otherwise, use an array of the required length, as the following code shows:

    const int MaxStackLimit = 1024;
    Span<byte> buffer = inputLength <= MaxStackLimit ? stackalloc byte[MaxStackLimit] : new byte[inputLength];
    

    Note

    Because the amount of memory available on the stack depends on the environment in which the code is executed, be conservative when you define the actual limit value.

  • Avoid using stackalloc inside loops. Allocate the memory block outside a loop and reuse it inside the loop.

The content of the newly allocated memory is undefined. You should initialize it, either with a stackalloc initializer, or a method like Span<T>.Clear before it's used.

Important

Not initializing memory allocated by stackalloc is an important difference from the new operator. Memory allocated using the new operator is initialized to the 0 bit pattern.

You can use array initializer syntax to define the content of the newly allocated memory. The following example demonstrates various ways to do that:

Span<int> first = stackalloc int[3] { 1, 2, 3 };
Span<int> second = stackalloc int[] { 1, 2, 3 };
ReadOnlySpan<int> third = stackalloc[] { 1, 2, 3 };

// Using collection expressions:
Span<int> fourth = [1, 2, 3];
ReadOnlySpan<int> fifth = [1, 2, 3];

In expression stackalloc T[E], T must be an unmanaged type and E must evaluate to a non-negative int value. When you use the collection expression syntax to initialize the span, the compiler may use stack allocated storage for a span if it won't violate ref safety.

Security

The use of stackalloc automatically enables buffer overrun detection features in the common language runtime (CLR). If a buffer overrun is detected, the process is terminated as quickly as possible to minimize the chance that malicious code is executed.

C# language specification

For more information, see the Stack allocation section of the C# language specification and the Permit stackalloc in nested contexts feature proposal note.

See also