Compartir a través de


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#.

Consulte también