Quelqu'un at-il déjà utilisé stackalloc
lors de la programmation en C #? Je sais ce qui se passe, mais la seule fois où cela apparaît dans mon code est par accident, car Intellisense le suggère lorsque je commence à taper static
, par exemple.
Bien que cela ne soit pas lié aux scénarios d'utilisation de stackalloc
, je fais en fait une quantité considérable d'interopérabilité héritée dans mes applications, donc je pouvais de temps en temps recourir à du code unsafe
. Mais néanmoins, je trouve généralement des moyens d'éviter complètement unsafe
.
Et puisque la taille de la pile pour un seul thread dans .Net est ~ 1 Mo (corrigez-moi si je me trompe), je suis encore plus réservé d'utiliser stackalloc
.
Y a-t-il des cas pratiques où l'on pourrait dire: "c'est exactement la bonne quantité de données et de traitement pour que je me mette en danger et utilise stackalloc
"?
La seule raison d'utiliser stackalloc
est la performance (que ce soit pour les calculs ou l'interopérabilité). En utilisant stackalloc
au lieu d'un tableau alloué au tas, vous créez moins de pression GC (le GC doit s'exécuter moins), vous n'avez pas besoin d'épingler les tableaux, il est plus rapide à allouer qu'un tableau de tas, un il est automatiquement libéré à la sortie de la méthode (les tableaux alloués en tas ne sont désalloués que lors de l'exécution du GC). De plus, en utilisant stackalloc
au lieu d'un allocateur natif (comme malloc ou l'équivalent .Net), vous gagnez également de la vitesse et une désallocation automatique à la sortie de la portée.
En termes de performances, si vous utilisez stackalloc
, vous augmentez considérablement les chances de succès du cache sur le processeur en raison de la localisation des données.
J'ai utilisé stackalloc pour allouer des tampons pour le travail DSP en temps réel [proche]. C'était un cas très spécifique où les performances devaient être aussi cohérentes que possible. Notez qu'il y a une différence entre la cohérence et le débit global - dans ce cas, je n'étais pas préoccupé par les allocations de tas étant trop lentes, juste avec le non déterminisme de la récupération de place à ce stade du programme. Je ne l'utiliserais pas dans 99% des cas.
stackalloc
n'est pertinent que pour le code non sécurisé. Pour le code managé, vous ne pouvez pas décider où allouer les données. Les types de valeur sont alloués sur la pile par défaut (sauf s'ils font partie d'un type de référence, auquel cas ils sont alloués sur le tas). Les types de référence sont alloués sur le tas.
La taille de pile par défaut pour une application Vanilla .NET simple est de 1 Mo, mais vous pouvez la modifier dans l'en-tête PE. Si vous démarrez explicitement des threads, vous pouvez également définir une taille différente via la surcharge du constructeur. Pour les applications ASP.NET, la taille de pile par défaut n'est que de 256 Ko, ce qui est quelque chose à garder à l'esprit si vous basculez entre les deux environnements.
Initialisation Stackalloc des travées. Dans les versions précédentes de C #, le résultat de stackalloc ne pouvait être stocké que dans une variable locale de pointeur. Depuis C # 7.2, stackalloc peut désormais être utilisé dans le cadre d'une expression et peut cibler une plage, ce qui peut être fait sans utiliser le mot clé unsafe. Ainsi, au lieu d'écrire
Span<byte> bytes;
unsafe
{
byte* tmp = stackalloc byte[length];
bytes = new Span<byte>(tmp, length);
}
Vous pouvez écrire simplement:
Span<byte> bytes = stackalloc byte[length];
Ceci est également extrêmement utile dans les situations où vous avez besoin d'espace de travail pour effectuer une opération, mais souhaitez éviter d'allouer de la mémoire de tas pour des tailles relativement petites
Span<byte> bytes = length <= 128 ? stackalloc byte[length] : new byte[length];
... // Code that operates on the Span<byte>
Source:C # - All About Span: exploration d'un nouveau pilier .NET