выражение 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
во вложенных контекстах в примечании.