Partager via


Expression stackalloc (référence C#)

Une expression stackalloc alloue un bloc de mémoire dans la pile. Un bloc de mémoire alloué dans la pile pendant l’exécution de la méthode est automatiquement supprimé lorsque cette méthode retourne un résultat. Vous ne pouvez pas libérer explicitement la mémoire allouée avec stackalloc. Un bloc de mémoire alloué dans la pile n’est pas soumis au nettoyage de la mémoire et ne doit pas être épinglé avec une instruction fixed.

Vous pouvez attribuer le résultat d’une expression stackalloc à une variable d’un des types suivants :

  • System.Span<T> ou System.ReadOnlySpan<T>, comme le montre l’exemple suivant :

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

    Vous n’avez pas l’obligation d’utiliser un contexte unsafe lorsque vous affectez un bloc de mémoire alloué dans la pile à une variable Span<T> ou ReadOnlySpan<T>.

    Lorsque vous travaillez avec ces types, vous pouvez utiliser une expression stackalloc les expressions conditionnelles ou d’affectation, comme le montre l’exemple suivant :

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

    Vous pouvez utiliser une expression stackalloc ou une expression de collection dans d’autres expressions chaque fois qu’une variable Span<T> ou ReadOnlySpan<T> est autorisée, comme le montre l’exemple suivant :

    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
    

    Remarque

    Nous vous recommandons d’utiliser les types Span<T> ou ReadOnlySpan<T> pour travailler avec la mémoire allouée dans la pile quand cela est possible.

  • Un type pointeur, comme illustré dans l’exemple suivant :

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

    Comme le montre l’exemple précédent, vous devez utiliser un contexte unsafe lorsque vous travaillez avec des types pointeurs.

    Dans le cas des types pointeur, vous pouvez utiliser une expression stackalloc uniquement dans une déclaration de variable locale pour initialiser la variable.

La quantité de mémoire disponible dans la pile est limitée. Si vous allouez trop de mémoire dans la pile, une StackOverflowException est levée. Pour éviter cela, respectez les règles ci-dessous :

  • Limitez la quantité de mémoire que vous allouez avec stackalloc. Par exemple, si la taille de mémoire tampon prévue est inférieure à une certaine limite, vous allouez la mémoire dans la pile ; sinon, utilisez un tableau de la longueur requise, comme le montre le code suivant :

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

    Notes

    Étant donné que la quantité de mémoire disponible dans la pile dépend de l’environnement dans lequel le code est exécuté, soyez prudent lorsque vous définissez la valeur limite réelle.

  • Évitez d’utiliser des boucles internes stackalloc. Allouez le bloc de mémoire en dehors d’une boucle et réutilisez-le à l’intérieur de la boucle.

Le contenu de la mémoire nouvellement allouée n’est pas défini. Vous devez l’initialiser, soit avec un stackalloc initialiseur, soit une méthode comme Span<T>.Clear avant son utilisation.

Important

L’initialisation de la mémoire allouée par stackalloc est une différence importante par rapport à l’opérateur new . La mémoire allouée à l’aide de l’opérateur new est initialisée au modèle 0 bits.

Vous pouvez utiliser la syntaxe d’initialiseur de tableau pour définir le contenu de la mémoire nouvellement allouée. L’exemple suivant illustre différentes manières de le faire :

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

Dans l’expression stackalloc T[E], T doit être un type non managé et E doit être évalué à une valeur int non négative. Quand vous utilisez la syntaxe d’expression de collection pour initialiser l’étendue, le compilateur peut utiliser le stockage alloué à la pile pour une étendue, s’il n’enfreint pas la sécurité de la référence.

Sécurité

L’utilisation de stackalloc active automatiquement les fonctionnalités de détection des dépassements de mémoire tampon dans le Common Language Runtime (CLR). Si un dépassement de mémoire tampon est détecté, le processus est terminé aussi rapidement que possible pour réduire les risques d’exécution de code malveillant.

spécification du langage C#

Pour plus d’informations, consultez la section Allocation de piles de la spécification de langage C# et la note de proposition de fonctionnalité Autoriserstackalloc dans des contextes imbriqués.

Voir aussi