Le tas et la pile Java en Java divisent la mémoire en deux types: l'un est la mémoire de pile et l'autre est la mémoire du tas.
Certains types de variables de base définis dans les fonctions et les variables de référence des objets 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 l'espace mémoire pour la variable dans la pile. Lorsque la portée de la variable dépasse la portée de la variable, 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 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 collectionneur automatique de la machine virtuelle Java. Une fois qu'un tableau ou un objet a été généré dans le tas, une variable spéciale peut être définie dans la pile. La valeur de cette variable est égale à la première adresse du tableau ou de l'objet dans la mémoire du tas. Cette variable spéciale dans la pile devient une variable de référence pour le tableau ou l'objet. À l'avenir, vous pouvez utiliser la variable de référence dans la mémoire de pile dans le programme pour accéder au tableau ou à l'objet dans le tas. La variable de référence est équivalente à un alias ou un nom de code pour le tableau ou l'objet.
Les variables de référence sont des variables ordinaires. Lorsqu'il est défini, la mémoire est allouée sur la pile. Les variables de référence sont libérées en dehors de la portée lorsque le programme s'exécute. Le tableau et l'objet lui-même 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 et l'objet, la mémoire de tas occupée par le tableau et l'objet lui-même ne sera pas publié. Le tableau et l'objet ne deviennent des ordures que lorsqu'il n'y a pas de variable de référence pointant vers lui, et ne peut plus être utilisé, mais il est toujours en train d'occuper de la mémoire et est libéré par le collecteur des ordures à un moment incertain. C'est aussi la principale 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 en java
Java divise la mémoire en deux types: l'un est la mémoire de pile et l'autre est la mémoire du tas.
1. La pile et le tas sont les deux endroits utilisés par Java pour stocker les données en RAM. Contrairement à C ++, Java gère automatiquement les piles et les tas, et les programmeurs ne peuvent pas configurer des piles ou des tas directement.
2. L'avantage de la pile est que la vitesse d'accès est plus rapide que le tas, après les registres situés directement dans le CPU. 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é. De plus, les données de pile peuvent être partagées. L'avantage du tas est qu'il peut allouer dynamiquement la taille de la mémoire et que la durée de vie n'a pas à être racontée au compilateur à l'avance. Le collecteur de déchets de Java collectera automatiquement les données qui ne sont plus utilisées. Mais l'inconvénient est que la mémoire doit être allouée dynamiquement au moment de l'exécution, la vitesse d'accès est plus lente.
3. Il existe deux types de données en Java.
L'un est les types de base (types primitifs), il existe 8 types, à savoir int, court, long, octet, flotteur, double, booléen, char (note,
Il n'y a pas de type de base de chaîne). Ce type de définition est défini par une forme telle que int a = 3; long b = 255L; et est appelé une variable automatique. Il convient de noter que la variable automatique contient des valeurs littérales, pas des instances de la classe, c'est-à-dire pas des références à la classe, et il n'y a pas de classe ici. Par exemple, int a = 3; Ici, A est une référence pointant vers le type int,
Poignent la valeur littérale de 3. En raison de la taille de ces valeurs littérales, la durée de vie de ces valeurs littérales peut être connue (ces valeurs littérales sont définies fixement dans un bloc de programme, et après les sorties du bloc de programme, la valeur du champ disparaît).
Pour poursuivre la vitesse, il existe dans la pile.
De plus, une caractéristique spéciale très importante de la pile est que les données de la pile peuvent être partagées. Supposons que nous définissons en même temps:
int a = 3;
int b = 3;
Le compilateur traite d'abord int a = 3; Il créera d'abord une référence à la variable A dans la pile, puis découvrira s'il y a une adresse avec une valeur littérale de 3. Si elle n'est pas trouvée, elle ouvrira une adresse avec la valeur littérale de 3, puis pointer A vers l'adresse de 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 littérale de 3 dans la pile, B est directement pointé vers l'adresse de 3. De cette façon, A et B pointent les deux à 3 en même temps.
Il est particulièrement important de noter que cette référence littérale est différente de celle des objets de classe. En supposant que les références de deux objets de classe pointent vers un objet en même temps, si une variable de référence d'objet modifie l'état interne de l'objet, l'autre variable de référence d'objet reflète immédiatement ce changement. Au lieu de cela, la modification de sa valeur par une référence littérale ne fera pas modifier une autre valeur en conséquence. Comme dans l'exemple ci-dessus, après avoir défini les valeurs de A et B, que A = 4; Ensuite, B ne sera pas égal à 4, ou égal à 3. À l'intérieur du compilateur, lorsque A = 4 est rencontré, il recouvrera s'il y a une valeur littérale de 4 dans la pile. Sinon, rouvrez l'adresse pour stocker la valeur de 4; S'il existe déjà, pointez directement A vers cette adresse. Par conséquent, la variation de la valeur A n'affectera pas la valeur b.
Un autre type consiste à emballer des données de classe, telles que entier, chaîne, double, etc. qui enveloppe les types de données de base correspondants. Toutes ces données de classe existent dans le tas. Java utilise la nouvelle instruction () pour afficher le compilateur et ne crée que dynamiquement au besoin au moment de l'exécution, il est donc plus flexible, mais l'inconvénient est qu'il prend plus de temps.
En Java, il y a six endroits différents où les données peuvent être stockées:
1. Registre. Il s'agit de la zone de stockage la plus rapide car elle est située dans un endroit différent des autres zones de stockage - le processeur. Cependant, le nombre de registres est extrêmement limité, de sorte que les registres sont alloués par le compilateur en fonction des exigences. Vous ne pouvez pas le contrôler directement, et vous ne pouvez pas ressentir de signes de l'existence du registre dans le programme.
2. Stack. Situé dans la RAM à usage général, mais avec son "pointeur de pile", vous pouvez obtenir le support du processeur. Si le pointeur de pile se déplace vers le bas, une nouvelle mémoire est allouée; S'il monte, ces souvenirs sont libérés. Il s'agit d'un moyen rapide et efficace d'allouer le stockage, juste en seconde où les registres. Lors de la création d'un programme, le compilateur Java doit connaître la taille exacte et le cycle de vie de toutes les données stockées dans la pile, car elle doit générer le code correspondant afin de déplacer le pointeur de pile de haut en bas. Cette contrainte limite la flexibilité du programme, donc bien que certaines données JA VA soient stockées sur la pile - en particulier les références d'objets, les objets Java n'y sont pas stockés.
3. Heap. Un pool de mémoire universel (existe également dans RAM) pour stocker les soi-disant objets Java. L'avantage du tas est que le compilateur n'a pas besoin de savoir combien de zones de stockage à allouer à partir du tas, ni de savoir combien de temps les données stockées dureront dans le tas. Par conséquent, il y a une grande flexibilité dans l'allocation de stockage dans le tas. Lorsque vous devez créer un objet, il vous suffit d'écrire une ligne de code simple dans un nouveau. Lors de l'exécution de cette ligne de code, elle stockera et allouera automatiquement le tas. Bien sûr, le code correspondant doit être payé pour cette flexibilité. Il faut plus de temps pour allouer le stockage avec le tas que pour le stocker avec la pile.
4. Stockage statique. "statique" signifie ici "en position fixe". Le stockage statique stocke les données qui ont toujours existé lorsque le programme est en cours d'exécution. Vous pouvez utiliser le mot-clé statique pour identifier qu'un élément spécifique d'un objet est statique, mais l'objet Java lui-même n'est jamais stocké dans un espace de stockage statique.
5. Stockage constant. Les valeurs constantes sont généralement stockées directement dans le code du programme, et il est sûr de le faire car ils ne seront jamais modifiés. Parfois, dans un système intégré, la constante elle-même est séparée des autres parties, donc dans ce cas, il est facultatif de le mettre dans la ROM.
6. Stockage non Ram. Si les données survivent complètement en dehors du programme, elles peuvent être laissées sans aucun contrôle du programme et peuvent exister lorsque le programme n'est pas en cours d'exécution.
En termes de vitesse, il existe une relation comme suit:
Enregistrer <pile <tas <Autre
"Le passage ci-dessus est extrait de" Thinking in Java ""
Question 1:
String str1 = "ABC"; String str2 = "ABC"; System.out.println (str1 == str2); //vrai
Question 2:
String str1 = new String ("ABC"); String str2 = new String ("ABC"); System.out.println (str1 == str2); // FAUX Question 3:
String S1 = "JA"; String S2 = "VA"; String S3 = "Java"; String S4 = S1 + S2; System.out.println (S3 == S4); // False System.out.println (S3.Equals (S4)); // Vrai
Certains types de variables de base 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 cette variable dans la pile. Lorsque la portée de la variable dépasse la variable, 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 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.
Plus précisément: la pile et le tas sont les deux endroits utilisés par Java pour stocker les données en RAM. Contrairement à C ++, Java gère automatiquement les piles et les tas, et les programmeurs ne peuvent pas configurer des piles ou des tas directement.
Le tas 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 la durée de vie n'a pas à être racontée au compilateur à l'avance, car elle alloue dynamiquement la mémoire au moment de 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 variables (, int, court, long, octet, flottant, double, booléen, char) et objets.
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:
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.
La chaîne est une données d'emballage spéciales. Peut être utilisé:
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 est de créer d'abord une variable STR à l'objet de la classe String dans la pile, puis de découvrir s'il y a "ABC" stocké dans la pile. Sinon, stockez "ABC" sur la pile 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.
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.
String str1 = new String ("ABC"); String str2 = new String ("ABC"); System.out.println (str1 == str2); // FAUX La 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. (Pas nécessairement, car s'il n'y a pas à l'avance, il sera créé. C'est la création de l'objet. S'il y en a déjà, pointez-vous vers l'objet d'origine)! 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. En raison de la nature immuable de la classe String, lorsque la variable de chaîne doit transformer fréquemment sa valeur, vous devriez envisager d'utiliser la classe StringBuffer pour améliorer l'efficacité du programme.