stackalloc-Ausdruck (C#-Referenz)

Ein stackalloc-Ausdruck ordnet einen Speicherblock im Stapel zu. Ein während der Ausführung der Methode im Stapel zugeordneter Speicherblock wird automatisch verworfen, wenn diese Methode zurückgegeben wird. Sie können den mit stackalloc zugeordneten Arbeitsspeicher nicht explizit freigeben. Ein im Stapel zugeordneter Arbeitsspeicherblock unterliegt nicht der automatischen Speicherbereinigung und muss nicht mit einer fixed-Anweisung angeheftet werden.

Sie können das Ergebnis eines stackalloc-Ausdrucks einer Variablen mit einem der folgenden Typen zuweisen:

  • System.Span<T> oder System.ReadOnlySpan<T>, wie im folgenden Beispiel gezeigt:

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

    Sie müssen keinen unsicheren Kontext verwenden, wenn Sie der Variablen Span<T> oder ReadOnlySpan<T> einen im Stapel zugeordneten Speicherblock zuweisen.

    Wenn Sie mit diesen Typen arbeiten, können Sie einen stackalloc-Ausdruck in bedingten oder Zuweisungsausdrücken verwenden, wie das folgende Beispiel zeigt:

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

    Sie können einen stackalloc-Ausdruck oder einen Sammelausdruck innerhalb anderer Ausdrücke verwenden, wenn eine Span<T> oder ReadOnlySpan<T> Variable erlaubt ist, wie das folgende Beispiel zeigt:

    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
    

    Hinweis

    Wir empfehlen, die Typen Span<T> oder ReadOnlySpan<T> zu verwenden, um nach Möglichkeit mit dem im Stapel zugeordneten Speicher zu arbeiten.

  • Ein Zeigertyp, wie im folgenden Beispiel gezeigt:

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

    Wie das vorhergehende Beispiel zeigt, müssen Sie einen unsafe-Kontext verwenden, wenn Sie mit Zeigertypen arbeiten.

    Im Fall von Zeigertypen können Sie einen stackalloc-Ausdruck nur in einer lokalen Variablendeklaration zum Initialisieren der Variable verwenden.

Die Menge des verfügbaren Speichers im Stapel ist begrenzt. Wenn Sie zu viel Speicher im Stapel zuordnen, wird eine StackOverflowException ausgelöst. Beachten Sie die folgenden Regeln, um dies zu vermeiden:

  • Begrenzen Sie die Speichermenge, die Sie mit stackalloc zuordnen. Wenn die vorgesehene Puffergröße beispielsweise einen bestimmten Grenzwert unterschreitet, weisen Sie den Speicher auf dem Stapel zu. Verwenden Sie andernfalls ein Array der erforderlichen Länge, wie im folgenden Code gezeigt:

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

    Hinweis

    Da die Menge des auf im Stapel verfügbaren Speichers von der Umgebung abhängt, in der der Code ausgeführt wird, sollten Sie bei der Festlegung des tatsächlichen Grenzwerts konservativ vorgehen.

  • Vermeiden Sie die Verwendung von stackalloc in Schleifen. Ordnen Sie den Speicherblock außerhalb einer Schleife zu, und verwenden Sie ihn innerhalb der Schleife wieder.

Der Inhalt des neu zugeordneten Speichers ist undefiniert. Er sollte vor Verwendung initialisiert werden. Beispielsweise können Sie die Span<T>.Clear-Methode verwenden, die alle Elemente auf den Standardwert des Typs T festlegt.

Sie können mit der Arrayinitialisierungssyntax den Inhalt des neu zugeordneten Speichers definieren. Das folgende Beispiel zeigt verschiedene Möglichkeiten, dies zu erreichen:

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

Im Ausdruck stackalloc T[E] muss T ein nicht verwalteter Typ sein und E in einen nicht negativen int-Wert ausgewertet werden. Wenn Sie die Syntax des Sammelausdrucks verwenden, um den Bereich zu initialisieren, kann der Compiler den vom Stapel zugewiesenen Speicher für einen Bereich verwenden, wenn dies die Verweissicherheit nicht verletzt.

Security

Mit der Verwendung von stackalloc werden automatisch Funktionen zum Erkennen eines Pufferüberlaufs in der Common Language Runtime (CLR) aktiviert. Wenn ein Pufferüberlauf erkannt wird, wird der Vorgang so schnell wie möglich beendet, damit das Risiko der Ausführung von schädlichem Code verringert wird.

C#-Sprachspezifikation

Weitere Informationen finden Sie im Abschnitt Stapelzuordnung der C#-Sprachspezifikation sowie im Vorschlag zum Feature Zulassen von stackalloc in geschachtelten Kontexten.

Weitere Informationen