Udostępnij za pośrednictwem


wyrażenie stackalloc (odwołanie w C#)

Wyrażenie stackalloc przydziela blok pamięci na stosie. Blok pamięci przydzielonej do stosu utworzony podczas wykonywania metody jest automatycznie odrzucany po powrocie tej metody. Nie można jawnie zwolnić pamięci przydzielonej za pomocą stackallocpolecenia . Blok pamięci przydzielonej do stosu nie podlega wyrzucaniu pamięci i nie musi być przypięty za pomocąfixed instrukcji .

Wynik wyrażenia można przypisać stackalloc do zmiennej jednego z następujących typów:

  • System.Span<T> lub System.ReadOnlySpan<T>, jak pokazano w poniższym przykładzie:

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

    Nie musisz używać niebezpiecznego kontekstu podczas przypisywania bloku pamięci przydzielonej do stosu do zmiennej Span<T> lubReadOnlySpan<T>.

    Podczas pracy z tymi typami można użyć stackalloc wyrażenia w wyrażeniach warunkowych lub przypisania, jak pokazano w poniższym przykładzie:

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

    Możesz użyć stackalloc wyrażenia lub wyrażenia kolekcji wewnątrz innych wyrażeń, gdy zmienna Span<T> lub ReadOnlySpan<T> jest dozwolona, jak pokazano w poniższym przykładzie:

    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
    

    Uwaga

    Zalecamy używanie typów Span<T> lub ReadOnlySpan<T> do pracy z przydzieloną pamięcią stosu, gdy jest to możliwe.

  • Typ wskaźnika, jak pokazano w poniższym przykładzie:

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

    Jak pokazano w poprzednim przykładzie, należy użyć unsafe kontekstu podczas pracy z typami wskaźników.

    W przypadku typów wskaźników można użyć stackalloc wyrażenia tylko w deklaracji zmiennej lokalnej, aby zainicjować zmienną.

Ilość pamięci dostępnej na stosie jest ograniczona. Jeśli przydzielisz za dużo pamięci na stosie, zostanie zgłoszony wyjątek StackOverflowException . Aby tego uniknąć, postępuj zgodnie z poniższymi regułami:

  • Ogranicz ilość pamięci przydzielanej za pomocą stackallocpolecenia . Jeśli na przykład zamierzony rozmiar buforu jest niższy niż określony limit, należy przydzielić pamięć na stosie; w przeciwnym razie użyj tablicy wymaganej długości, jak pokazano w poniższym kodzie:

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

    Uwaga

    Ponieważ ilość pamięci dostępnej na stosie zależy od środowiska, w którym jest wykonywany kod, należy zachować podczas definiowania rzeczywistej wartości limitu.

  • Unikaj używania stackalloc pętli wewnątrz. Przydziel blok pamięci poza pętlą i użyj go ponownie wewnątrz pętli.

Zawartość nowo przydzielonej pamięci jest niezdefiniowana. Należy go zainicjować za pomocą inicjatora stackalloc lub metody, takiej jak Span<T>.Clear przed jej użyciem.

Ważne

Inicjowanie pamięci przydzielonej przez stackalloc program jest ważną różnicą między operatorem new . Pamięć przydzielona new przy użyciu operatora jest inicjowana do wzorca 0-bitowego.

Składnia inicjatora tablicy umożliwia zdefiniowanie zawartości nowo przydzielonej pamięci. W poniższym przykładzie pokazano różne sposoby, aby to zrobić:

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

W wyrażeniu stackalloc T[E]T musi być typem niezarządzanym i E musi zostać obliczona wartość int nieujemna. Jeśli używasz składni wyrażeń kolekcji do inicjowania zakresu, kompilator może używać przydzielonego magazynu stosu dla zakresu, jeśli nie naruszy bezpieczeństwa ref.

Zabezpieczenia

Użycie funkcji automatycznego włączania stackalloc funkcji wykrywania przepełnienia buforu w środowisku uruchomieniowym języka wspólnego (CLR). Jeśli zostanie wykryte przepełnienie buforu, proces zostanie zakończony tak szybko, jak to możliwe, aby zminimalizować prawdopodobieństwo wykonania złośliwego kodu.

specyfikacja języka C#

Aby uzyskać więcej informacji, zobacz sekcję Alokacja stosu specyfikacji języka C# i uwaga dotycząca propozycji funkcji Zezwól stackalloc na zagnieżdżone konteksty.

Zobacz też