Cet article explique principalement son principe de fonctionnement en détail en analysant la pile, le tas et le pool constant d'allocation de mémoire Java.
1. Prototype de mémoire de machine virtuelle Java
Register : Nous n'avons aucun contrôle sur le programme. Stack : stocke les types de données de base et les références d'objets, mais l'objet lui-même n'est pas stocké sur la pile, mais est stocké dans le tas : stocke les données générées avec le nouveau domaine statique. : est stocké dans l'objet. Pool de constantes membres statiques défini avec static : stocke les constantes de stockage non RAM : espace de stockage permanent tel que le disque dur.
2. Piscine constante
Le pool constant fait référence au pool constant déterminé au moment de la compilation et enregistré dans la mémoire compilée. Quelques données dans le fichier de classe. En plus des valeurs constantes (finales) qui contiennent divers types de base (tels que int, long, etc.) et types d'objets (tels que String et tableaux) définis dans le code, il contient également quelques références symboliques sous forme de texte. , tel que:
1. Noms complets des classes et des interfaces ;
2. Nom du champ et descripteur ;
3. Méthodes, noms et descripteurs.
La machine virtuelle doit maintenir un pool constant pour chaque type chargé. Le pool de constantes est un ensemble ordonné de constantes utilisées par ce type, y compris des constantes directes (constantes de chaîne, entières et à virgule flottante) et des références symboliques à d'autres types, champs et méthodes. Pour les constantes String, leurs valeurs se trouvent dans le pool de constantes. Le pool de constantes dans la JVM existe sous la forme d'une table en mémoire. Pour le type String, il existe une table CONSTANT_String_info de longueur fixe utilisée pour stocker les valeurs de chaîne littérale. Remarque : Cette table stocke uniquement les valeurs de chaîne littérale, pas les symboles. . Cela dit, vous devez avoir une compréhension claire de l'emplacement de stockage des valeurs de chaîne dans le pool constant. Lorsque le programme est exécuté, le pool de constantes sera stocké dans la zone de méthode au lieu du tas.
3. Pile dans l'allocation de mémoire Java
L'unité de base de la pile est le frame (ou stack frame) : à chaque fois qu'un thread Java s'exécute, la machine virtuelle Java alloue une pile Java au thread. Lorsque le thread exécute une certaine méthode Java, il pousse un cadre dans la pile Java. Ce cadre est utilisé pour stocker des paramètres, des variables locales, des opérandes, des résultats d'opérations intermédiaires, etc. Une fois l'exécution de cette méthode terminée, le cadre sera retiré de la pile. Toutes les données de la pile Java sont privées et aucun autre thread ne peut accéder aux données de la pile du thread. Certains types de base de données variables et de variables de référence d'objet définis dans la fonction sont alloués dans la mémoire de pile de la fonction. Lorsqu'une variable est définie dans un bloc de code, Java alloue de l'espace mémoire pour la variable sur la pile. Lorsque la variable quitte la portée, Java libère automatiquement l'espace mémoire alloué à la variable et l'espace mémoire peut être utilisé immédiatement. être utilisé à d’autres fins.
4. Tas dans l'allocation de mémoire Java
Le tas de la machine virtuelle Java est utilisé pour stocker les objets et les tableaux créés par new. La mémoire allouée dans le tas est gérée par le mécanisme automatique de garbage collection de la machine virtuelle Java. Pour faire simple, par rapport à la pile, le tas est principalement utilisé pour stocker des objets Java, et la pile est principalement utilisée pour stocker les références d'objets... Une fois qu'un tableau ou un objet est généré dans le tas, une variable spéciale peut également être défini dans la pile, de sorte que La valeur de cette variable dans la pile est égale à la première adresse du tableau ou de l'objet dans la mémoire tas. Cette variable dans la pile devient la variable de référence du tableau ou de l'objet. Une variable de référence équivaut à donner un nom à un tableau ou un objet. Vous pouvez ensuite utiliser la variable de référence dans la pile pour accéder au tableau ou à l'objet dans le tas du programme. Une variable de référence équivaut à donner un nom à un tableau ou un objet.
Les variables de référence sont des variables ordinaires qui sont allouées sur la pile lorsqu'elles sont définies. Les variables de référence sont libérées une fois que le programme s'exécute en dehors de sa portée. Les tableaux et les objets eux-mêmes sont alloués dans le tas Même si le programme s'exécute en dehors du bloc de code où se trouve l'instruction utilisant new pour générer le tableau ou l'objet, la mémoire occupée par le tableau et l'objet lui-même ne sera pas libérée. les objets n'ont pas de variables de référence pointant vers eux, ils deviennent des déchets et ne peuvent plus être utilisés, mais ils occupent toujours l'espace mémoire et seront collectés (libérés) par le garbage collector à un moment indéterminé plus tard. C'est aussi la raison pour laquelle Java occupe plus de mémoire. En fait, les variables de la pile pointent vers les variables de la mémoire tas. Il s'agit d'un pointeur en Java !
Le tas de Java est une zone de données d'exécution à partir de laquelle les objets de classe allouent de l'espace. Ces objets sont créés via des instructions telles que new, newaray, anewarray et multianewarray, et ils ne nécessitent pas que le code du programme soit explicitement libéré. Le tas est collecté par garbage collection. Responsable, l'avantage du tas est qu'il peut allouer dynamiquement la taille de la mémoire, et la durée de vie n'a pas besoin d'être indiquée au compilateur à l'avance, car il alloue dynamiquement la mémoire au moment de l'exécution, et le garbage collector de Java collectera automatiquement celles qui ne sont plus utilisées. données. Mais l'inconvénient est qu'en raison de la nécessité d'allouer dynamiquement de la mémoire au moment de l'exécution, la vitesse d'accès est lente.
L'avantage de la pile est que la vitesse d'accès est plus rapide que celle du tas, juste derrière le registre, et que les données de la pile peuvent être partagées. Mais l’inconvénient est que la taille et la durée de vie des données stockées dans la pile doivent être déterminées et qu’il y a un manque de flexibilité. La pile stocke principalement certains types de données variables de base (int, short, long, byte, float, double, boolean, char) et des descripteurs d'objet (références).
Une particularité très importante de la pile est que les données stockées dans la pile peuvent être partagées. Supposons que nous définissions également :
int a=3; int b=3; Le compilateur traite d'abord int a = 3 ; il crée d'abord une référence à la variable a sur la pile, puis vérifie s'il y a une valeur de 3 sur la pile. il définira 3 Stockez-le dans, puis pointez a vers 3. Ensuite, traitez int b = 3 après avoir créé la variable de référence de b, car il y a déjà une valeur de 3 sur la pile, b sera pointé directement vers 3. De cette façon, a et b apparaissent en même temps, tous deux indiquent le cas 3.
À ce stade, si a = 4 est à nouveau défini ; alors le compilateur recherchera à nouveau s'il y a une valeur 4 dans la pile. Sinon, il stockera 4 et fera un point sur 4 s'il existe déjà. pointera directement a vers cette adresse. Par conséquent, les changements dans la valeur de a n’affecteront pas la valeur de b.
Il est à noter que ce type de partage de données est différent du partage de références de deux objets pointant vers un objet en même temps, car dans ce cas la modification de a n'affectera pas b, elle est complétée par le compilateur, qui est bénéfique pour économiser de l'espace. Si une variable de référence d'objet modifie l'état interne de l'objet, cela affectera une autre variable de référence d'objet.