Expressão stackalloc (referência de C#)

A expressão stackalloc aloca um bloco de memória na pilha. Um bloco de memória alocado na pilha criado durante a execução do método é descartado automaticamente quando esse método é retornado. Você não pode liberar explicitamente a memória alocada com stackalloc. Um bloco de memória alocado por pilha não está sujeito a Coleta de lixo e não precisa ser fixado com uma fixed instrução.

Você pode atribuir o resultado de uma expressão stackalloc a uma variável de um dos seguintes tipos:

  • System.Span<T> ou System.ReadOnlySpan<T> como mostrado no exemplo a seguir:

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

    Você não precisa usar um contexto unsafe quando atribui um bloco de memória alocado na pilha a uma variável Span<T> ou ReadOnlySpan<T>.

    Ao trabalhar com esses tipos, você pode usar uma expressão stackalloc em condicional ou expressões de atribuição, como mostra o seguinte exemplo:

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

    Você pode usar uma expressão stackalloc ou uma expressão de coleção dentro de outras expressões sempre que uma variável Span<T> ou ReadOnlySpan<T> for permitida, como mostra o exemplo a seguir:

    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
    

    Observação

    É recomendável usar os tipos Span<T> ou ReadOnlySpan<T> sempre que possível para trabalhar com memória alocada na pilha.

  • Um tipo de ponteiro, como mostra o seguinte exemplo:

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

    Como mostra o exemplo anterior, você precisa usar um contexto unsafe ao trabalhar com tipos de ponteiro.

    No caso de tipos de ponteiro, você pode usar uma expressão stackalloc apenas em uma declaração de variável local para inicializar a variável.

A quantidade de memória disponível na pilha é limitada. Se você alocar muita memória na pilha, um StackOverflowException será lançado. Para evitar isso, siga as regras abaixo:

  • Limite a quantidade de memória alocada com stackalloc. Por exemplo, se o tamanho do buffer pretendido estiver abaixo de um determinado limite, você alocará a memória na pilha; caso contrário, use uma matriz do comprimento necessário, como mostra o seguinte código:

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

    Observação

    Como a quantidade de memória disponível na pilha depende do ambiente no qual o código é executado, seja conservador ao definir o valor de limite real.

  • Evite usar stackalloc dentro de loops. Aloque o bloco de memória fora de um loop e reutilize-o dentro do loop.

O conteúdo da memória recém-alocada é indefinido. Você deve inicializá-lo antes do uso. Por exemplo, você pode usar o método Span<T>.Clear que define todos os itens com o valor padrão do tipo T.

Você pode usar a sintaxe do inicializador de matriz para definir o conteúdo da memória recém-alocada. O seguinte exemplo demonstra várias maneiras de fazer isso:

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

Na expressão stackalloc T[E], T deve ser um tipo não gerenciado e E deve ser avaliado como um valor int não negativo. Quando você usa a sintaxe de expressão de coleção para inicializar a extensão, o compilador pode usar o armazenamento alocado de pilha para uma extensão se ele não violar a segurança ref.

Segurança

O uso de stackalloc habilita automaticamente os recursos de detecção de estouro de buffer no CLR (Common Language Runtime). Se for detectada uma estouro de buffer, o processo será encerrado assim que possível para minimizar a chance de o código mal-intencionado ser executado.

Especificação da linguagem C#

Para obter mais informações, consulte a seção de Alocação de pilha da Especificação da linguagem C# e a nota de proposta do recurso Permitir stackalloc em contextos aninhados.

Confira também