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


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

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

Справочные документы по языку C# описывают последнюю выпущенную версию языка C#. Она также содержит начальную документацию по функциям в общедоступных предварительных версиях для предстоящего языкового выпуска.

Документация определяет любую функцию, впервые представленную в последних трех версиях языка или в текущих общедоступных предварительных версиях.

Подсказка

Чтобы узнать, когда функция впервые появилась в C#, ознакомьтесь со статьей об истории версий языка C#.

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

  • 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;
    }
    

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

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

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

    Выражение или выражение коллекции можно использовать 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<int> numbers2 = [1, 2, 3, 4, 5, 6];
    var ind2 = numbers2.IndexOfAny([2, 4, 6, 8]);
    Console.WriteLine(ind2);  // 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 в циклах. Выделяйте блок памяти за пределами цикла и используйте его повторно внутри цикла.

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

Внимание

Не инициализация памяти, выделенной по stackalloc оператору, является важным отличием new от оператора. Память, выделенная с помощью new оператора, инициализируется в 0-битовом шаблоне.

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

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];

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

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

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

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

Дополнительные сведения см. в разделе выделения стекаспецификации языка C#.

См. также