выражение stackalloc (справочник по C#)

Выражение stackalloc выделяет блок памяти в стеке. Выделенный в стеке блок памяти, который создает этот метод, автоматически удаляется по завершении выполнения метода. Вы не можете явным образом освободить память, выделенную stackalloc. Выделенный в стеке блок памяти не подвергается сборке мусора, поэтому его не нужно закреплять с помощью инструкции fixed.

Результат выполнения выражения stackalloc можно присвоить переменной любого из следующих типов:

  • Начиная с версии C# 7.2, System.Span<T> или System.ReadOnlySpan<T>, как показано в следующем примере:

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

    Нет необходимости использовать небезопасный контекст при назначении выделенного в стеке блока памяти переменной Span<T> или ReadOnlySpan<T>.

    При работе с такими типами вы можете использовать выражение stackalloc в условном выражении или выражении присваивания, как показано в следующем примере:

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

    Начиная с версии C# 8.0, можно использовать выражение stackalloc внутри других выражений, если разрешена переменная Span<T> или ReadOnlySpan<T>, как показано в следующем примере:

    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<T> или ReadOnlySpan<T>.

  • Тип указателя, как показано в следующем примере.

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

    Как демонстрирует пример выше, при работе с типами указателей необходимо использовать контекст unsafe.

    В случае типов указателей можно использовать выражение stackalloc только в объявлении локальной переменной для инициализации переменной.

Объем доступной памяти в стеке ограничен. При выделении слишком большого объема памяти в стеке возникает исключение StackOverflowException. Чтобы избежать этого, следуйте приведенным ниже правилам.

  • Ограничьте объем памяти, выделенный stackalloc. Например, если предполагаемый размер буфера меньше определенного предела, то выделяется память в стеке. В противном случае используйте массив требуемой длины, как показано в следующем коде:

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

    Примечание

    Поскольку объем доступной памяти на стеке зависит от среды, в которой выполняется код, при определении фактического предельного значения следует использовать консервативное значение.

  • Старайтесь не использовать stackalloc в циклах. Выделяйте блок памяти за пределами цикла и используйте его повторно внутри цикла.

Содержимое только что выделенной памяти не определено. Его следует инициализировать перед использованием. Например, вы можете использовать метод Span<T>.Clear, который задает для всех элементов значение по умолчанию типа T.

Начиная с версии C# 7.3, вы можете использовать синтаксис инициализатора массива, чтобы определить содержимое для только что выделенной памяти. В следующем примере показано несколько способов сделать это:

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

В выражении stackalloc T[E]T должен иметь неуправляемый тип, а E — неотрицательное значение int.

Безопасность

При использовании stackalloc в среде CLR автоматически включается контроль переполнения буфера. Если буфер переполнен, процесс незамедлительно прерывается — это позволяет минимизировать риск исполнения вредоносного кода.

Спецификация языка C#

См. сведения о выделении памяти в стеке в спецификации языка C# и разрешении stackalloc во вложенных контекстах в примечании.

См. также