Programmation et développement logiciel

Les améliorations de .NET 11 cumulent les gains de performance, du JIT à la programmation asynchrone

Microsoft présente des centaines d’améliorations dans .NET 11, en mettant clairement l’accent sur le compilateur JIT, la réduction des allocations et l’amélioration des appels d’interfaces et de délégués, ainsi que sur la structure interne d’async/await. Les résultats publiés montrent que les gains proviennent de la suppression de vérifications, d’allocations et d’appels inutiles, plutôt que d’un changement unique et majeur.

2026-09-15
6 min de lecture
6 vues
فريق تحرير certi.news
Les améliorations de .NET 11 cumulent les gains de performance, du JIT à la programmation asynchrone

Dans un billet publié sur le .NET Blog le 15 septembre 2026, Microsoft présente des centaines d’améliorations intégrées à .NET 11 et les décrit comme le résultat cumulatif d’un travail portant sur le compilateur JIT, le runtime et les bibliothèques. L’idée centrale n’est pas l’existence d’une fonctionnalité unique qui doublerait les performances, mais la suppression de petits coûts récurrents : une vérification de limites qui n’est plus nécessaire, une allocation mémoire supprimée, un verrou ou un appel système évité, et des boucles qui s’exécutent avec moins de cycles processeur.

L’importance de ce type d’améliorations tient au fait qu’une grande partie d’entre elles ne nécessite ni modification du code des applications ni refonte de leur architecture. Le compilateur JIT transforme généralement le code intermédiaire IL produit par C#, F# et Visual Basic en instructions natives exécutées par le processeur. Lorsqu’il parvient à démontrer qu’un appel virtuel peut être dirigé vers un type déterminé, ou qu’une vérification donnée ne peut pas échouer, il peut produire des instructions plus courtes et améliorer les possibilités d’intégration des fonctions les unes dans les autres.

Amélioration de la suppression des abstractions

Une partie importante de l’article porte sur ce que Microsoft appelle la suppression des abstractions, c’est-à-dire la possibilité pour le runtime de contourner le coût d’exécution de certaines abstractions dont le développeur a besoin dans la conception du programme. Les appels d’interfaces et les méthodes virtuelles en sont des exemples : l’exécution traditionnelle peut devoir charger plusieurs pointeurs et effectuer un appel indirect, ce qui empêche d’intégrer la fonction appelée à la fonction en cours.

.NET 11 poursuit le développement de la « dévirtualisation gardée » (Guarded Devirtualization). Le JIT identifie le type le plus fréquent pendant l’exécution, crée un chemin rapide pour l’appeler directement, tout en conservant le chemin virtuel afin de garantir la validité de l’exécution si un autre type apparaît ultérieurement. Lorsque cela permet l’intégration de la fonction, d’autres optimisations deviennent possibles, comme la propagation des constantes, la suppression des branchements et l’élimination des vérifications de limites.

Le travail s’étend aux méthodes virtuelles génériques, aux modes ReadyToRun et NativeAOT, ainsi qu’aux implémentations par défaut des interfaces. L’article indique que ces améliorations peuvent accroître la taille du code lorsque les appels directs entraînent davantage d’intégration, mais qu’elles rendent la logique du programme plus visible pour l’optimiseur.

Moins d’allocations et un impact réduit sur le ramasse-miettes

.NET 11 continue également d’étendre l’analyse d’échappement (Escape Analysis), qui tente de déterminer si un objet créé dans une fonction dépasse la portée de celle-ci. S’il est établi qu’il ne sort pas de cette portée, le JIT peut éviter de le placer sur le tas managé, voire supprimer entièrement l’allocation dans certains cas, ce qui réduit la pression exercée sur le ramasse-miettes.

La source présente des exemples d’amélioration du boxing des valeurs Nullable, ainsi que de l’analyse conditionnelle de l’échappement lors de l’énumération de collections. Dans l’une des mesures, une allocation de 32 octets a disparu lors de l’énumération d’une collection construite à partir d’un champ d’instance, tandis que le temps d’exécution est passé de 13,874 nanosecondes dans .NET 10 à 2,674 nanosecondes dans .NET 11. Certaines situations utilisant des valeurs génériques ou des appels d’interfaces peuvent également éviter des allocations temporaires de 24 octets.

Ces chiffres concernent des opérations extrêmement petites ; ils ne doivent donc pas être interprétés comme une augmentation générale et constante des performances de chaque application. Leur principal intérêt est de révéler des modèles de code que le runtime peut optimiser, tandis que l’impact réel dépendra de la nature de l’application et de ses chemins critiques.

Les délégués et le runtime asynchrone

.NET 11 inclut des modifications de la représentation des délégués dans CoreCLR, notamment la suppression d’un champ de la taille d’un pointeur dans chaque objet délégué pour les processus 64 bits, soit une économie de 8 octets par délégué selon l’article. Les champs de représentation des délégués ont également été réorganisés dans NativeAOT, et certaines valeurs utilisées ensemble ont été placées côte à côte en mémoire afin d’améliorer leur accès sur des architectures comme Arm64.

Le billet présente également une nouvelle structure appelée « runtime async », qui transfère une partie de la responsabilité de la transformation des méthodes async/await du compilateur C# vers le JIT et le runtime. Dans le modèle traditionnel, le compilateur crée une machine à états contenant les champs nécessaires à la reprise, comme les paramètres, les variables locales, les awaiters et l’état d’exécution. Le nouveau modèle repose sur un contrat IL plus petit, puis laisse au runtime et au JIT les décisions liées à ce qui reste vivant aux points de suspension, à la manière d’organiser les objets de continuation et à la création du Task ou du ValueTask visible de l’extérieur.

Qu’est-ce qui change concrètement ?

Le principal enseignement éditorial de cette évolution est que .NET 11 mise autant sur l’amélioration du code existant que sur l’ajout de nouvelles API. Les applications qui utilisent intensivement les interfaces, les méthodes génériques, les délégués, l’énumération et les opérations asynchrones peuvent en bénéficier sans modifications directes du code source, mais l’ampleur de l’amélioration variera selon le processeur, le système d’exploitation, les paramètres du runtime et la nature de la charge.

Microsoft recommande de tester les résultats avec BenchmarkDotNet, en installant .NET 10 et .NET 11 et en exécutant le même code sur les deux versions. Elle rappelle que les mesures publiées sont des tests extrêmement précis et peuvent être influencées par le matériel, les autres processus et les paramètres de l’environnement. Les résultats d’un microbenchmark ne suffisent donc pas à décider d’une mise à niveau ni à démontrer une amélioration globale ; il est nécessaire de mesurer les charges réelles de l’application avant de tirer des conclusions plus larges.

Source de l’actualité
ف
Auteur

فريق تحرير certi.news

Dans la même catégorie

À lire également

Voir toutes les actualités