Partilhar via


expressão stackalloc (referência C#)

Uma stackalloc expressão aloca um bloco de memória na pilha. Um bloco de memória alocado por pilha criado durante a execução do método é automaticamente descartado quando esse método retorna. Não é possível liberar explicitamente a memória alocada com stackalloco . Um bloco de memória alocado por pilha não está sujeito à coleta de lixo e não precisa ser fixado com uma fixed instrução.

A referência da linguagem C# documenta a versão mais recentemente lançada da linguagem C#. Contém também documentação inicial para funcionalidades em versões preliminares públicas para a próxima versão da linguagem.

A documentação identifica qualquer funcionalidade introduzida pela primeira vez nas últimas três versões da língua ou em pré-visualizações públicas atuais.

Sugestão

Para saber quando uma funcionalidade foi introduzida pela primeira vez em C#, consulte o artigo sobre o histórico de versões da linguagem C#.

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

  • System.Span<T> ou System.ReadOnlySpan<T>, como mostra o exemplo a seguir:

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

    Não precisas de usar um contexto inseguro quando atribuis um bloco de memória alocado pela pilha a uma Span<T> variável ou.ReadOnlySpan<T>

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

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

    Você pode usar uma stackalloc expressão ou uma expressão de coleção dentro de outras expressões sempre que uma Span<T>ReadOnlySpan<T> ou variável 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
    

    Nota

    Use Span<T> ou ReadOnlySpan<T> tipos para trabalhar com a memória alocada à pilha sempre que possível.

  • Um tipo de ponteiro, como mostra o exemplo a seguir:

    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ê deve usar um unsafe contexto ao trabalhar com tipos de ponteiro.

    Para tipos de ponteiros, pode usar uma stackalloc expressão apenas numa declaração local de variável 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 é lançado. Para evitar essa exceção, siga estas regras:

  • Limite a quantidade de memória alocada com stackalloco . 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 código a seguir:

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

    Nota

    Como a quantidade de memória disponível na pilha depende do ambiente em que o código corre, seja conservador ao definir o valor limite real.

  • Evite usar stackalloc loops internos. 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, seja com um stackalloc inicializador ou um método como Span<T>.Clear antes de ser usado.

Importante

Não inicializar a memória alocada por stackalloc é uma diferença importante do new operador. A memória alocada usando o new operador é inicializada no padrão de bits 0.

Você pode usar a sintaxe do inicializador de matriz para definir o conteúdo da memória recém-alocada. O exemplo a seguir 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 avaliar para um valor int não negativo. Quando usas a sintaxe da expressão de coleção para inicializar o span, o compilador pode usar armazenamento alocado pela pilha para um span se não violar a segurança da referência.

Segurança

O uso stackalloc automático ativa as funcionalidades de deteção de overrun de buffer no tempo de execução da common language (CLR). Se o runtime detetar um overrun do buffer, termina o processo o mais rapidamente possível para reduzir a probabilidade de código malicioso ser executado.

Especificação da linguagem C#

Para obter mais informações, consulte a seção Alocação de pilha da especificação da linguagem C#.

Consulte também