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 przez stackallocprogram . Blok pamięci przydzielonej do stosu nie podlega wyrzucaniu pamięci i nie musi być przypięty przez instrukcjęfixed .

Dokumentacja języka C# zawiera ostatnio wydaną wersję języka C#. Zawiera również początkową dokumentację dla funkcjonalności w publicznych wersjach testowych nadchodzącego wydania języka.

Dokumentacja identyfikuje dowolną funkcję po raz pierwszy wprowadzoną w ostatnich trzech wersjach języka lub w bieżącej publicznej wersji zapoznawczej.

Wskazówka

Aby dowiedzieć się, kiedy funkcja została po raz pierwszy wprowadzona w języku C#, zapoznaj się z artykułem dotyczącym historii wersji języka C#.

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> lub ReadOnlySpan<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

    Używaj Span<T> typów lub ReadOnlySpan<T> do pracy z pamięcią przydzieloną do 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;
        }
    }
    

    Podczas pracy z typami wskaźników należy użyć unsafe kontekstu.

    Uwaga

    Funkcja wersji zapoznawczej bezpieczeństwa pamięci dostępna w języku C# 15 umożliwia konwertowanie stackalloc wyrażenia na wskaźnik poza kontekstem unsafe . Operacje, które uzyskują dostęp do przydzielonej pamięci za pośrednictwem wskaźnika, nadal wymagają unsafe kontekstu.

    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 uniknąć tego wyjątku, wykonaj następujące reguły:

  • Ogranicz ilość pamięci przydzielanej przy użyciu polecenia stackalloc. Jeśli na przykład zamierzony rozmiar buforu jest niższy od określonego limitu, przydziel 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[inputLength] : new byte[inputLength];
    

    Uwaga

    Ponieważ ilość pamięci dostępnej na stosie zależy od środowiska, w którym jest uruchamiany kod, zachowaj ostrożność 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 zainicjować go przed użyciem za pomocą inicjatora stackalloc lub metody, takiej jak Span<T>.Clear.

Ważne

Inicjowanie pamięci przydzielonej przez stackalloc program jest ważną różnicą między operatorem new . Pamięć przydzielona przy użyciu new 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. Gdy używasz składni wyrażenia kolekcji do inicjowania zakresu, kompilator może użyć magazynu przydzielonego stosu dla zakresu, jeśli nie narusza bezpieczeństwa ref.

Zabezpieczenia

Funkcja automatycznego stackalloc włączania funkcji wykrywania przepełnień buforu w środowisku uruchomieniowym języka wspólnego (CLR). Jeśli środowisko uruchomieniowe wykryje przepełnienie buforu, zakończy proces tak szybko, jak to możliwe, aby zmniejszyć prawdopodobieństwo uruchomienia złośliwego kodu.

specyfikacja języka C#

Aby uzyskać więcej informacji, zobacz sekcję Alokacja stosuspecyfikacji języka C#.

Zobacz też