Introduction
• Présentation
• Lorsque vous déclarez une variable derrière quoi arrivé?
•Tas et pile
•Types de valeur et types de référence
•Quels sont les types de valeur et lesquels sont les types de référence ?
•Boxing et unboxing
•Problèmes de performances du boxing et du unboxing
1 Aperçu
Cet article expliquera six concepts importants : tas. , pile, types de valeur, types de référence, boxing et unboxing. Cet article commencera par expliquer les changements qui se produisent au sein du système lorsque vous définissez une variable, puis se concentrera sur le duo de stockage : le tas et la pile. Plus tard, nous explorerons les types valeur et les types référence et expliquerons les bases importantes de ces deux types.
Cet article utilisera un code simple pour montrer l'impact sur les performances causé par le processus de boxing et de unboxing. Veuillez le lire attentivement.
2. Que se passe-t-il en coulisses lorsque vous déclarez une variable ?
Lorsque vous définissez une variable dans une application .NET, un bloc de mémoire lui est alloué dans la RAM. Cette mémoire contient trois choses : le nom de la variable, le type de données de la variable et la valeur de la variable.
Ce qui précède explique brièvement ce qui se passe en mémoire, mais le type exact de mémoire auquel votre variable sera allouée dépend du type de données. Il existe deux types de mémoire allouable dans .NET : la pile et le tas. Dans les prochaines sections, nous tenterons de comprendre en détail ces deux types de stockage.
3.
public void Method1() { // Line 1 int i=4; // Line 2 int y=2; //Line 3 class1 cls1 = new class1(); }
•Un autre point important à noter ici est que le pointeur de référence de l'objet est alloué sur la pile. Par exemple : l'instruction de déclaration Class1 cls1 ; n'alloue pas de mémoire pour l'instance de Class1, elle crée simplement un pointeur de référence pour la variable cls1 sur la pile (et définit sa position par défaut sur null). Ce n'est que lorsqu'il rencontrera le nouveau mot-clé qu'il allouera de la mémoire à l'objet sur le tas.
•En quittant cette méthode Method1 (le plaisir) : Maintenant, l'instruction de contrôle d'exécution commence à quitter le corps de la méthode. À ce moment, tout l'espace mémoire alloué aux variables sur la pile sera effacé. En d'autres termes, dans l'exemple ci-dessus, toutes les variables liées au type int seront extraites de la pile une par une selon la méthode "LIFO", dernier entré, premier sorti.
•Il convient de noter qu'il ne libérera pas les blocs de mémoire dans le tas pour le moment. Les blocs de mémoire dans le tas seront nettoyés ultérieurement par le garbage collector.
Maintenant, beaucoup de nos amis développeurs doivent être curieux de savoir pourquoi il existe deux types de stockage différents ? Pourquoi ne pouvons-nous pas allouer tous les blocs de mémoire à un seul type de stockage ?
Si vous regardez assez attentivement, les types de données primitifs ne sont pas complexes, ils contiennent simplement des valeurs comme « int i = 0 ». Les types de données d'objet sont plus compliqués ; ils font référence à d'autres objets ou à d'autres types de données primitifs. En d’autres termes, ils contiennent des références à plusieurs autres valeurs et ces valeurs doivent être stockées en mémoire une par une. Les types d'objet nécessitent une mémoire dynamique tandis que les types primitifs nécessitent une mémoire statique. Si l'exigence est une mémoire dynamique, alors il lui allouera de la mémoire sur le tas, sinon, il l'allouera sur la pile.
4. Types de valeur et types de référence
Maintenant que nous avons compris les concepts de pile et de tas, il est temps de comprendre les types de valeur. et références La notion de type. Les types valeur conservent les données et la mémoire au même emplacement, tandis qu’un type référence possède un pointeur vers la zone mémoire réelle.
Grâce à la figure ci-dessous, nous pouvons voir un type de données entier nommé i, et sa valeur est attribuée à un autre type de données entier nommé j. Leurs valeurs sont stockées sur la pile.
Lorsque nous attribuons une valeur de type int à une autre valeur de type int, cela crée en fait une copie complètement différente. Autrement dit, si vous modifiez la valeur de l’un, l’autre ne changera pas. Par conséquent, ces types de données sont appelés « types de valeur ».
Lorsque nous créons un objet et attribuons cet objet à un autre objet, ils pointent tous les deux vers la même zone de mémoire comme indiqué dans l'extrait de code ci-dessous. Par conséquent, lorsque nous attribuons obj à obj1, ils pointent tous les deux vers la même zone du tas. En d’autres termes, si l’on change l’un d’entre eux à ce moment, l’autre sera affecté, ce qui explique aussi pourquoi on les appelle « types référence ».
5. Quels sont les types valeur et quels sont les types référence ?
Dans .NET, le fait qu'une variable soit stockée sur la pile ou dans le tas dépend entièrement du type de données auquel elle appartient. Par exemple : « String » ou « Object » sont des types de référence, tandis que d'autres types de données primitifs .NET seront alloués sur la pile. La figure ci-dessous montre en détail lesquels des types prédéfinis .NET sont des types valeur et lesquels sont des types référence.
6. Emballage et déballage
Maintenant, vous avez déjà beaucoup de bases théoriques. Il est maintenant temps de comprendre comment les connaissances ci-dessus sont utilisées dans la programmation réelle. L'une des principales implications dans les applications est de comprendre les problèmes de consommation de performances qui se produisent lorsque les données sont déplacées de la pile vers le tas, et vice versa.
Considérez l'extrait de code suivant lorsque nous convertissons un type valeur en type référence, les données seront déplacées de la pile vers le tas. Inversement, lorsque nous convertissons un type référence en type valeur, les données sont également déplacées du tas vers la pile.
Qu'il passe de la pile au tas ou du tas à la pile, cela aura inévitablement un certain impact sur les performances du système.
En conséquence, deux nouveaux termes sont apparus : lorsque les données sont converties d'un type valeur en un type référence, le processus est appelé "boxing", et le processus de conversion d'un type référence en un type de valeur est appelé « boxing ».
Si vous compilez le code ci-dessus et le visualisez dans ILDASM (un outil de décompilation IL), vous constaterez que dans le code IL, à quoi ressemblent le boxing et le unboxing comme. La figure ci-dessous montre le code IL généré après la compilation de l'exemple de code.
7. Problèmes de performances de la boxe et du déballage
Afin de le comprendre Quel type d'impact sur les performances le boxing et le unboxing auront-ils ? Nous exécutons les deux méthodes de fonction illustrées dans la figure ci-dessous 10 000 fois en boucle. La première méthode comporte des opérations de boxe, l’autre non. Nous utilisons un objet Chronomètre pour surveiller la consommation de temps.
La méthode avec opération de boxe a pris 3 542 millisecondes, tandis que la méthode sans opération de boxe n'a pris que 2 477 millisecondes, soit une différence de plus d'une seconde. De plus, cette valeur augmentera également à mesure que le nombre de cycles augmentera. En d’autres termes, nous devrions essayer d’éviter les opérations de boxing et de unboxing. Dans un projet, si vous avez besoin de boxer et de boxer, réfléchissez bien s'il s'agit d'une opération absolument indispensable, sinon, essayez de ne pas l'utiliser.
Bien que l'extrait de code ci-dessus n'affiche pas le déballage, mais l'effet s'applique également au déballage. Vous pouvez implémenter le déballage en écrivant du code et tester sa consommation de temps via Stopwatch.
Voici les six concepts importants dans .NET : pile, tas, type de valeur, type de référence, boxing et unboxing. Pour plus de contenu connexe, veuillez prêter attention au site Web chinois PHP (m.sbmmt.com). )!