L'allocation et la gestion de la mémoire Java sont l'une des technologies de base de Java. Nous avons précédemment introduit les connaissances de la gestion de la mémoire de Java, de la fuite de mémoire et de la collection Java Garbage. Aujourd'hui, nous allons une fois de plus aller profondément dans le noyau Java et présenter en détail la connaissance de Java dans l'allocation de la mémoire. Généralement, Java impliquera les domaines suivants lors de l'allocation de la mémoire:
◆ Registre: nous ne pouvons pas le contrôler dans le programme
◆ Pile: stocke les types de données de base et les références aux objets, mais l'objet lui-même n'est pas stocké dans la pile, mais est stocké dans le tas (l'objet qui sort de nouveau)
◆ tas: stocker les données générées à l'aide de nouveaux
◆ Domaine statique: membres statiques stockés dans un objet défini avec statique
◆ Pool constant: Constantes de magasin
◆ Stockage non Ram: espace de stockage permanent tel que le disque dur
Empiler l'allocation de la mémoire Java
Certains types de base de données variables définis dans la fonction et les variables de référence de l'objet sont tous alloués dans la mémoire de pile de la fonction.
Lorsqu'une variable est définie dans un bloc de code, Java alloue l'espace mémoire pour la variable dans la pile. Lorsque la variable quitte la portée, Java libérera automatiquement l'espace mémoire alloué à la variable et l'espace mémoire peut être utilisé séparément immédiatement. La taille des données et le cycle de vie de la pile sont certains, et ces données disparaissent lorsqu'aucune référence ne pointe des données.
Tas dans l'allocation de la mémoire Java
La mémoire du tas est utilisée pour stocker des objets et des tableaux créés par Nouveau. La mémoire allouée dans le tas est gérée par le collecteur automatique automatique de la machine virtuelle Java.
Une fois qu'un tableau ou un objet est généré dans le tas, une variable spéciale peut être définie 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 du tas, et la variable dans la pile devient une variable de référence pour le tableau ou l'objet. Une variable de référence est équivalente à un nom donné à un tableau ou un objet. Vous pouvez utiliser les variables de référence dans la pile du programme pour accéder au tableau ou à l'objet dans le tas. Une variable de référence est équivalente à un nom donné à un tableau ou un objet.
Les variables de référence sont des variables ordinaires, qui sont attribuées sur la pile lorsqu'elles sont définies. Les variables de référence sont publiées une fois le programme en dehors de sa portée. Le tableau et l'objet 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 trouvent les instructions qui utilisent de nouvelles 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 publiée. Le tableau et l'objet ne deviennent des ordures que lorsqu'il n'y a pas de variable de référence le pointant vers, et ne peut pas être utilisé, mais occupe toujours l'espace mémoire. Il est collecté (libéré) par le collecteur des ordures à un moment incertain. C'est aussi la raison pour laquelle Java prend plus de mémoire.
En fait, les variables du point de pile à des variables dans la mémoire du tas, qui est le pointeur en Java!
Tas et pile
Le tas de Java est une zone de données d'exécution, à partir de laquelle les objets allouent l'espace. Ces objets sont établis grâce à des instructions telles que New, NewArray, AnewArray et MultianeWarray. Ils ne nécessitent pas que le code du programme soit explicitement libéré. Le tas est responsable de la collecte des ordures. L'avantage du tas est qu'il peut allouer dynamiquement la taille de la mémoire et n'a pas à indiquer au compilateur à l'avance car il alloue dynamiquement la mémoire à l'exécution. Le collecteur de déchets de Java collectera automatiquement les données qui ne sont plus utilisées. Mais l'inconvénient est que, car il doit allouer dynamiquement la mémoire au moment de l'exécution, la vitesse d'accès est plus lente.
L'avantage de la pile est que la vitesse d'accès est plus rapide que le tas, la suite uniquement vers les registres, et les données de pile peuvent être partagées. Mais l'inconvénient est que la taille des données et la durée de vie de la pile doivent être déterministes et manquer de flexibilité. La pile stocke principalement certains types de base de données variables (int, court, long, octet, float, double, booléen, char) et des poignées d'objet (références).
Une caractéristique spéciale très importante de la pile est que les données existantes dans la pile peuvent être partagées. Supposons que nous définissons en même temps:
Code java
int a = 3;
int b = 3;
Le compilateur traite d'abord int a = 3; Il créera d'abord une référence dans la pile avec une variable A, puis découvrira s'il y a une valeur de 3 dans la pile. S'il n'est pas trouvé, il stockera 3 puis pointer A à 3. Processus 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 dans la pile, B est directement pointé vers 3. De cette façon, A et B pointent les deux à 3 en même temps.
À l'heure actuelle, si A = 4 est à nouveau relevé; Ensuite, le compilateur recherchera à nouveau s'il y a une valeur 4 dans la pile. Sinon, magasin 4 et point A à 4; S'il existe déjà, pointez A vers cette adresse directement. Par conséquent, la variation de la valeur A n'affectera pas la valeur b.
Il convient de noter que ce partage de données est différent du partage des 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, il est fait par le compilateur, ce qui est propice à l'espace de sauvegarde. Une variable de référence d'objet modifie l'état interne de cet objet et affectera une autre variable de référence d'objet.
Code java
1.Int i1 = 9;
2.Int I2 = 9;
3.Int i3 = 9;
4.Public statique final int int1 = 9;
5.Publique final statique int int2 = 9;
6.Publique final statique int int3 = 9;
Pour les variables des membres et les variables locales: les variables membres sont des variables définies à l'intérieur de la méthode et de la classe; Les variables locales sont des variables définies à l'intérieur de la méthode ou du bloc de déclaration. Les variables locales doivent être initialisées.
Les paramètres formels sont des variables locales et les données des variables locales existent dans la mémoire de la pile. Les variables locales dans la mémoire de la pile disparaissent à mesure que la méthode disparaît.
Les variables des membres sont stockées dans des objets dans le tas et sont collectées par le collecteur des ordures.
Comme dans le code suivant:
Code java
Classe Date de naissance {private int Day; Mois d'int privé; année int privée; Date de naissance publique (int d, int m, int y) {day = d; mois = m; année = y; } omit get, set Method ……} public class test {public static void main (String args []) {int date = 9; Test test = nouveau test (); test.change (date); Date de naissance D1 = nouvelle date de naissance (7,7,1970); } public void change1 (int i) {i = 1234; }Pour le code ci-dessus, la date est une variable locale, I, D, M, Y sont tous des paramètres formels en tant que variables locales, et le jour, le mois et l'année sont des variables de membres. Analysons les modifications lors de l'exécution du code:
1. La méthode principale commence à s'exécuter: Int Date = 9;
Date des variables locales, des types de base, des références et des valeurs sont tous présents sur la pile.
2. Test test = nouveau test ();
Le test est une référence d'objet, il existe sur la pile et l'objet (nouveau test ()) existe sur le tas.
3. Test.Change (date);
I est une variable locale, et la référence et la valeur sont présentes dans la pile. Lorsque le changement de méthode est exécuté, je disparaîtrai de la pile.
4. Date de naissance D1 = nouvelle date de naissance (7,7,1970);
D1 est une référence d'objet et existe dans la pile. Les objets (New Birthdate ()) existent dans le tas, où D, M, Y sont des variables locales stockées dans la pile, et leurs types sont les types de base, de sorte que leurs données sont également stockées dans la pile. jour, mois, année sont des variables membres, et ils sont stockés dans le tas (new naissance ()). Lorsque le constructeur de la date de naissance est exécuté, D, M, Y disparaîtra de la pile.
5. Une fois la méthode principale exécutée, la variable de date, le test et la référence D1 disparaîtront de la pile, et new Test (), New Birthdate () attendra la collecte des ordures.
Piscine constante
Les pools constants se réfèrent à certaines données déterminées pendant la période de compilation et sont enregistrées dans le fichier .class compilé.
En plus de contenir les valeurs constantes (finale) de divers types de base (tels que int, long, etc.) et les types d'objets (tels que la chaîne et les tableaux) définis dans le code, il contient également des références symboliques sous forme de texte, telles que:
◆ Les noms entièrement qualifiés des classes et interfaces;
◆ Le nom et le descripteur du champ;
◆ Méthodes et noms et descripteurs.
Si la période de compilation a été créée (définie directement en doubles guillemets), elle sera stockée dans le pool constant, et si elle peut être déterminée par la période d'exécution (à partir du nouveau), elle sera stockée dans le tas. Pour les chaînes avec égaux, il n'y a toujours qu'une seule copie dans le pool constant et la copie multiple dans le tas.
La chaîne est une données d'emballage spéciales. Peut être utilisé:
Code java
String str = new String ("ABC"); String str = "ABC";Il existe deux formulaires à créer. La première consiste à utiliser new () pour créer un nouvel objet, qui sera stocké dans le tas. Un nouvel objet est créé à chaque fois qu'il est appelé. Le deuxième type consiste à créer d'abord une variable STR dans l'objet de la classe String dans la pile, puis à utiliser une référence symbolique pour savoir s'il y a "ABC" dans le pool constant de chaîne. Sinon, stockez "ABC" dans la piscine constante de chaîne et laissez STR pointer "ABC". S'il y a déjà "ABC", laissez directement Str vers "ABC".
Lorsque vous comparez si les valeurs de la classe sont égales, utilisez la méthode equals (); Lorsque vous testez si les références des deux classes de wrapper pointent vers le même objet, utilisez == et utilisez l'exemple ci-dessous pour illustrer la théorie ci-dessus.
Code java
String str1 = "ABC"; String str2 = "ABC"; System.out.println (str1 == str2); //vrai
On peut voir que STR1 et STR2 pointent vers le même objet.
Code java
String str1 = new String ("ABC"); String str2 = new String ("ABC"); System.out.println (str1 == str2); // FAUXLa nouvelle méthode consiste à générer différents objets. Générez un à la fois.
Par conséquent, dans la deuxième voie, plusieurs chaînes "ABC" sont créées, et il n'y a qu'un seul objet en mémoire. Cette méthode d'écriture est bénéfique et enregistre l'espace mémoire. Dans le même temps, il peut améliorer la vitesse d'exécution du programme dans une certaine mesure, car le JVM décidera automatiquement s'il est nécessaire de créer un nouvel objet basé sur la situation réelle des données dans la pile. Pour le code de String str = new String ("ABC");, de nouveaux objets sont créés dans le tas, que leurs valeurs de chaîne soient égales ou non, s'il est nécessaire de créer de nouveaux objets, augmentant ainsi le fardeau du programme.
D'un autre côté, note: lorsque nous définissons une classe en utilisant un format tel que String str = "ABC";, nous tenons toujours pour acquis que nous créons un objet STR de la classe String. Inquiétez-vous pour le piège! L'objet n'a peut-être pas été créé! Et peut-être simplement indiquer un objet qui a été créé précédemment. Ce n'est que via la nouvelle méthode () que nous pouvons nous assurer qu'un nouvel objet est créé à chaque fois.
Plusieurs exemples de problème de mise en commun constant de cordes
Exemple 1:
Code java
String S0 = "Kvill"; String S1 = "Kvill"; String S2 = "KV" + "Ill"; System.out.println (S0 == S1); System.out.println (S0 == S2); Le résultat est: TrueTrue
Analyse: Tout d'abord, nous devons savoir que le résultat est que Java garantira qu'une constante de chaîne n'a qu'une seule copie.
Parce que S0 et S1 dans l'exemple sont les deux constantes de chaîne, elles sont déterminées pendant la période de compilation, donc S0 == S1 est vrai; et "KV" et "Ill" sont également des constantes de chaîne. Lorsqu'une chaîne est connectée par plusieurs constantes de chaîne, c'est certainement une constante de chaîne elle-même, donc S2 est également analysé dans une constante de chaîne pendant la période de compilation, donc S2 est également une référence à "Kvill" dans le pool constant. Nous obtenons donc S0 == S1 == S2;
Exemple 2:
Exemple:
Code java
Analyse: Les chaînes créées avec une nouvelle chaîne () ne sont pas des constantes et ne peuvent pas être déterminées pendant la période de compilation, de sorte que les chaînes créées par New String () ne sont pas placées dans le pool constant, ils ont leur propre espace d'adressage.
S0 est également une application de "Kvill" dans le pool constant. S1 ne peut pas être déterminé pendant la période de compilation, il s'agit donc d'une référence au nouvel objet "Kvill" créé lors de l'exécution. S2 ne peut pas être déterminé pendant la période de compilation car il a la seconde moitié de la nouvelle chaîne ("Ill"), il s'agit donc également d'une application de l'objet nouvellement créé "Kvill"; Si vous les comprenez, vous saurez pourquoi ce résultat est obtenu.
Exemple 3:
Code java
String a = "a1"; chaîne b = "a" + 1; System.out.println ((a == b)); // result = true string a = "true"; string b = "a" + "true"; system.out.println ((a == b)); // result = true string a = "a3.4"; chaîne b = "a" + 3.4; system.out.println ((a == b)); // Résultat = vrai
Analyse: Pour la connexion JVM des constantes de chaîne, le JVM optimise la connexion "+" de la chaîne constante à la valeur connectée après la période de compilation du programme. Prenez "A" + 1 comme exemple. Après optimisation par le compilateur, il est déjà A1 dans la classe. Pendant la période de compilation, la valeur de la constante de chaîne est déterminée, donc le résultat final du programme ci-dessus est vrai.
Exemple 4:
Code java
String a = "ab"; chaîne bb = "b"; chaîne b = "a" + bb; system.out.println ((a == b)); // résultat = faux
Analyse: Pour les références de chaîne dans JVM, comme il y a des références de chaîne dans la connexion "+" des chaînes, la valeur référencée ne peut pas être déterminée pendant la période de compilation du programme, c'est-à-dire que "un" + BB ne peut pas être optimisé par le compilateur, et n'allait que dynamiquement et attribue la nouvelle adresse connectée à B pendant la période d'exécution du programme. Par conséquent, le résultat du programme ci-dessus est faux.
Exemple 5:
Code java
String a = "Ab"; chaîne finale bb = "b"; chaîne b = "a" + bb; system.out.println ((a == b)); // Résultat = vrai
Analyse: La seule différence entre [4] est que la chaîne BB est décorée d'une modification finale. Pour les variables modifiées finales, il est analysé comme une copie locale de la valeur constante au moment de la compilation et stocké dans son propre pool constant ou intégré dans son flux bytecode. Donc, à ce moment, les effets de "A" + BB et "A" + "B" sont les mêmes. Par conséquent, le résultat du programme ci-dessus est vrai.
Exemple 6:
Code java
String A = "AB"; chaîne finale bb = getBB (); chaîne b = "a" + bb; System.out.println ((a == b)); // result = falseprivate static string getBb () {return "b"; }Analyse: Le JVM fait référence à BB pour les chaînes, et sa valeur ne peut pas être déterminée pendant la période de compilation. Ce n'est qu'après avoir appelé la méthode pendant l'exécution du programme, la valeur de retour de la méthode et "A" sont connectées dynamiquement et l'adresse est attribuée à b. Par conséquent, le résultat du programme ci-dessus est faux.
À propos de la chaîne est immuable
D'après l'exemple ci-dessus, nous pouvons le découvrir:
String S = "A" + "B" + "C";
Il équivaut à String S = "ABC";
String a = "a";
String b = "b";
Chaîne c = "c";
Chaîne s = a + b + c;
Ceci est différent, le résultat final est égal à:
Code java
StringBuffer temp = new StringBuffer (); temp.APPEND (A) .APPEND (B) .APPEND (C); String S = temp.ToString ();
D'après les résultats de l'analyse ci-dessus, il n'est pas difficile de déduire que String utilise l'opérateur de connexion (+) pour analyser la raison de l'inefficacité, comme ce code:
Code java
classe publique test {public static void main (String args []) {String s = null; pour (int i = 0; i <100; i ++) {s + = "a"; }}}Chaque fois que + est terminé, un objet StringBuilder est généré, puis l'ajouta et le jette. La prochaine fois que la boucle arrivera, un objet StringBuilder sera régénéré, puis ajoutez la chaîne, et la boucle est terminée jusqu'à la fin. Si nous utilisons directement l'objet StringBuilder pour ajouter, nous pouvons enregistrer n - 1 le temps pour créer et détruire l'objet. Par conséquent, pour les applications qui nécessitent une concaténation de chaîne dans une boucle, l'opération d'ajout est généralement effectuée à l'aide d'objets StringBuffer ou StringBulider.
En raison de la nature immuable de la classe String, il y a beaucoup à dire à ce sujet. Tant que vous savez que l'instance de chaîne ne changera pas une fois qu'elle sera générée, par exemple: String str = "kv" + "Ill" + "" + "Ans"; Il y a 4 constantes de chaîne. Tout d'abord, «KV» et «Ill» génèrent «Kvill» en mémoire, puis «Kvill» et «» »générent« Kvill »et« »et« Kvill Ans »;
Utilisation finale et compréhension en chaîne
Code java
final StringBuffer a = new StringBuffer ("111"); final stringBuffer b = new StringBuffer ("222"); a = b; // Cette phrase ne se compile pas avant sa fin. Final StringBuffer a = new StringBuffer ("111"); A.APPEND ("222"); /// compiler après sa finOn peut voir que Final n'est valable que pour la "valeur" référencée (c'est-à-dire l'adresse mémoire). Il oblige la référence à ne pointer que l'objet qui a été initialement indiqué. La modification de son pointage entraînera une erreur de compilation. Quant aux modifications de l'objet vers lesquelles il pointe, final est irresponsable.
Résumer
La pile est utilisée pour stocker certaines données variables locales du type de données d'origine et des références aux objets (chaîne, tableau, objet, etc.) mais ne stocke pas le contenu d'objet
Les objets créés à l'aide du nouveau mot-clé sont stockés dans le tas.
Une chaîne est une classe de wrapper spéciale, et ses références sont stockées dans la pile, et le contenu de l'objet doit être déterminé en fonction de la méthode de création (pool constant et tas). Certains sont créés au moment de la compilation et stockés dans le pool de string constant, tandis que d'autres sont créés uniquement au moment de l'exécution. Utilisez le nouveau mot-clé et stocké dans le tas.
L'article ci-dessus parle brièvement de la différence entre la répartition de la mémoire Java + et l'emplacement de stockage des variables est tout le contenu que je partage avec vous. J'espère que vous pourrez vous faire référence et j'espère que vous pourrez soutenir Wulin.com plus.