Expresión stackalloc (referencia de C#)
La expresión stackalloc
asigna un bloque de memoria en la pila. Un bloque de memoria asignado a la pila creado durante la ejecución del método se descarta automáticamente cuando el método deja de ejecutarse. No puede liberar explícitamente memoria asignada con stackalloc
. Un bloque de memoria asignada a la pila no está sujeto a la recolección de elementos no utilizados y no tiene que fijarse con una instrucción fixed
.
Puede asignar el resultado de una expresión stackalloc
a una variable de uno de los siguientes tipos:
System.Span<T> o System.ReadOnlySpan<T>, tal como se muestra en el ejemplo siguiente:
int length = 3; Span<int> numbers = stackalloc int[length]; for (var i = 0; i < length; i++) { numbers[i] = i; }
No tiene que usar un contexto unsafe al asignar un bloque de memoria asignado a la pila para una variable Span<T> o ReadOnlySpan<T>.
Cuando se trabaja con esos tipos, puede usar una expresión
stackalloc
en expresiones condicionales o de asignación, como se muestra en el ejemplo siguiente:int length = 1000; Span<byte> buffer = length <= 1024 ? stackalloc byte[length] : new byte[length];
Se puede usar una expresión o colección de expresión
stackalloc
dentro de otras expresiones siempre que se permita una variable Span<T> o ReadOnlySpan<T>, como se muestra en el ejemplo siguiente: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
Nota:
Se recomienda usar los tipos Span<T> o ReadOnlySpan<T> para trabajar con memoria asignada a la pila siempre que sea posible.
Un tipo de puntero, como se muestra en el ejemplo siguiente:
unsafe { int length = 3; int* numbers = stackalloc int[length]; for (var i = 0; i < length; i++) { numbers[i] = i; } }
Como se muestra en el ejemplo anterior, se debe utilizar un contexto
unsafe
cuando se trabaja con tipos de puntero.En el caso de los tipos de puntero, solo se puede usar una expresión
stackalloc
en una declaración de variable local para inicializar la variable.
La cantidad de memoria disponible en la pila es limitada. Si asigna demasiada memoria en la pila, se produce una excepción StackOverflowException. Para evitarlo, siga estas reglas:
Limite la cantidad de memoria asignada con
stackalloc
. Por ejemplo, si el tamaño de búfer previsto está por debajo de un límite determinado, asigne la memoria en la pila; de lo contrario, use una matriz de la longitud necesaria, como se muestra en el código siguiente:const int MaxStackLimit = 1024; Span<byte> buffer = inputLength <= MaxStackLimit ? stackalloc byte[MaxStackLimit] : new byte[inputLength];
Nota:
Como la cantidad de memoria disponible en la pila depende del entorno en el que se ejecuta el código, debe ser conservador al definir el valor límite real.
Evite el uso de
stackalloc
dentro de bucles. Asigne el bloque de memoria fuera de un bucle y vuelva a usarlo dentro del bucle.
El contenido de la memoria recién asignada está sin definir. Debe inicializarlo, ya sea con un stackalloc
inicializador o un método como Span<T>.Clear antes de usarlo.
Importante
No inicializar la memoria asignada por stackalloc
es una diferencia importante del new
operador. La memoria asignada mediante el new
operador se inicializa en el patrón de 0 bits.
Se puede usar la sintaxis de inicializador de matriz para definir el contenido de la memoria recientemente asignada. En el ejemplo siguiente se muestran diversas formas de hacerlo:
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];
En la expresión stackalloc T[E]
, T
debe ser un tipo no administrado y E
debe evaluarse como un valor int no negativo. Cuando se usa la sintaxis de la expresión de colección para inicializar el intervalo, el compilador puede usar el almacenamiento asignado a la pila para un intervalo si no infringe la seguridad ref.
Seguridad
El uso de stackalloc
habilita automáticamente las características de detección de saturación del búfer en el entorno Common Language Runtime (CLR). Si se detecta saturación del búfer, se finaliza el proceso lo antes posible para minimizar el riesgo de que se ejecute código malintencionado.
Especificación del lenguaje C#
Para obtener más información, vea la sección sobre asignación de pila de la especificación del lenguaje C#.