1. Concepts de base
Chaque programme Java exécute générera un processus Java. Chaque processus Java peut contenir un ou plusieurs threads. Chaque processus Java correspond à une instance JVM unique, chaque instance JVM correspond à un tas et chaque fil a sa propre pile privée. Toutes les instances de classes (c'est-à-dire des objets) ou des tableaux (se référant au tableau lui-même, et non des références) créé par un processus sont placés dans le tas et partagés par tous les threads du processus. La mémoire de tas allouée dans Java est automatiquement initialisée, c'est-à-dire, lors de l'allocation de la mémoire à un objet, les variables de l'objet seront initialisées. Bien que l'espace de stockage de tous les objets de Java soit alloué dans le tas, la référence à cet objet est allouée dans la pile, c'est-à-dire lorsqu'un objet est créé, la mémoire est allouée dans le tas et la pile. La mémoire allouée dans le tas stocke en fait l'objet créé lui-même, tandis que la mémoire allouée dans la pile ne stocke que des références à l'objet tas. Lorsque la variable locale nouvelle sort, l'espace est alloué dans l'espace de pile et l'espace de tas. Lorsque le cycle de vie variable local se termine, l'espace de pile est immédiatement recyclé et la zone d'espace de tas attend que GC recycle.
Concept spécifique: La mémoire d'un JVM peut être divisée en trois domaines: tas, pile et zone de méthode (méthode, également appelée zone statique):
Zone de pile:
1. Tous les objets stockés sont des objets, et chaque objet contient des informations correspondant à celui-ci (le but de la classe est d'obtenir des instructions de fonctionnement);
2.JVM n'a qu'une seule zone de tas (tas) et est partagé par tous les threads. Le tas ne stocke pas les types de base et les références d'objets, mais seulement l'objet lui-même et le tableau lui-même;
Zone de pile:
1. Chaque thread contient une zone de pile, qui enregistre uniquement les références au type de données de base lui-même et aux objets personnalisés;
2. Les données (type primitif et référence d'objet) dans chaque pile sont privées et sont accessibles par d'autres piles;
3. La pile est divisée en 3 parties: zone variable de base, contexte de l'environnement d'exécution et zone d'instructions de fonctionnement (stockage des instructions de fonctionnement);
Zone de méthode (zone statique):
1. Partagé par tous les fils. La zone de méthode contient toutes les classes (la classe se réfère au code d'origine de la classe. Pour créer un objet de classe, le code de la classe doit être chargé dans la zone de méthode et initialisé) et des variables statiques.
2. La zone de méthode contient des éléments qui sont toujours uniques dans l'ensemble du programme, tels que la classe et les variables statiques.
2. Exemple de démonstration
Appmain.java
classe publique AppMain // En fonctionnement, JVM met tout le code AppMain dans la zone de la méthode {public static void main (String [] args) // La méthode principale elle-même est placée dans la zone de la méthode. {Échantillon test1 = nouvel échantillon ("test 1"); // Test1 est une référence, donc mis dans la zone de pile, l'échantillon est un objet personnalisé, qui doit être placé dans le tas. Échantillon test2 = nouvel échantillon ("test 2"); test1.printName (); test2.printName (); }} Sample de classe publique // En fonctionnement, JVM met toutes les informations d'AppMain dans la zone de la méthode {/ ** Exemple de nom * / nom de chaîne privée; // Après une nouvelle instance d'échantillon, la référence de nom est placée dans la zone de pile, le nom de la chaîne correspondant est placé dans le constructeur tas / ** constructeur * / public public (nom de chaîne) {this .name = name; } / ** output * / public void printname () // Lorsqu'il n'y a pas d'objet, la méthode d'impression est placée dans la zone de la méthode avec la classe d'échantillonnage. {System.out.println (name); }}Lors de l'exécution du programme, démarrez d'abord un processus de machine virtuelle Java. Ce processus trouve d'abord le fichier appmain.class à partir du chemin de classe, lit les données binaires dans le fichier, puis stocke les informations de classe de la classe AppMain dans la zone de méthode de la zone de données d'exécution. Il s'agit du processus de chargement de la classe AppMain.
Ensuite, la machine virtuelle Java localise le bytecode de la méthode principale () de la classe AppMain dans la zone de méthode et commence à exécuter ses instructions. La première déclaration de cette méthode Main () est:
La copie de code est la suivante:
Exemple de test1 = nouvel échantillon ("test1");
Le processus d'exécution de cette déclaration:
1. La machine virtuelle Java a trouvé les informations de type de la classe d'échantillonnage dans la zone de la méthode, mais elle n'a pas été trouvée, car la classe d'échantillon n'a pas été chargée dans la zone de la méthode (il peut être vu ici que les classes internes de Java existent séparément, et au début, elle ne sera pas chargée de la classe de contenu et ne sera pas chargée avant qu'elle ne soit utilisée). La machine virtuelle Java charge immédiatement la classe d'échantillonnage et stocke les informations de type de classe d'échantillonnage dans la zone de la méthode.
2. La machine virtuelle Java alloue d'abord la mémoire à une nouvelle instance d'échantillon dans la zone du tas et stocke une adresse mémoire dans la zone de méthode où les informations de type de classe d'échantillons sont stockées dans la mémoire de l'exemple d'instance.
3. Dans le processus JVM, chaque thread aura une pile d'appels de méthode, qui est utilisée pour suivre une série de processus d'appel de méthode pendant l'exécution du thread. Chaque élément de la pile est appelé trame de pile. Chaque fois qu'un thread appelle une méthode, un nouveau cadre sera poussé dans la pile de méthode. Les cadres ici sont utilisés pour stocker les paramètres de la méthode, des variables locales et des données temporaires pendant l'opération.
4. Test1 avant "=" est une variable (une référence à un échantillon d'objet) définie dans la méthode principale (), il sera donc ajouté à la pile d'appel de la méthode Java du thread principal qui exécute la méthode principale (). Et "=" pointera cette variable TEST1 vers l'instance d'échantillon dans la zone du tas.
5. Le JVM continue de créer une autre instance d'échantillon dans la zone du tas et ajoute une variable TEST2 à la pile d'appels de méthode de la méthode principale, qui pointe vers la nouvelle instance d'échantillon qui vient d'être créée dans la zone du tas.
6. Le JVM exécute leur méthode PrintName () à son tour. Lorsque la machine virtuelle Java exécute la méthode Test1.printName (), la machine virtuelle Java localise l'exemple d'instance dans la zone du tas basée sur la référence détenue par la variable locale Test1, puis localise le type de type de classe d'échantillonnage dans la méthode basée sur la référence par l'exemple d'échantillon, l'obtention ainsi le bytecode de la méthode PrintName (), puis exécute l'exécution des instructions contenues dans la méthode Printname () pour commencer.
Iii. Distinguer
La différence entre le tas et la pile en langue java:
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 (voir l'introduction ci-dessous pour plus de détails). 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.
2 types de données en Java:
L'un est les types primitifs, avec 8 catégories, à savoir int, court, long, octet, flottant, double, booléen, char (notez qu'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. Les variables automatiques ont des valeurs littérales, pas des cas de classes, c'est-à-dire qu'ils ne sont pas des références aux classes, 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, pointant la valeur littérale de 3. En raison de la taille et de la durée de vie de ces données littérales, ces valeurs littérales sont définies fixement dans un bloc de programme, et la valeur du champ disparaît après la sortie du bloc du programme) et existe dans la pile pour la poursuite de la vitesse.
La pile a une fonctionnalité très importante: les données qui existent 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 avec une 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.
Cette référence aux valeurs littérales 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.
4. Résumé
La structure d'allocation de la mémoire Java est encore très claire. Si vous voulez le comprendre à fond, vous pouvez vérifier les livres liés à la JVM. Dans Java, la chose la plus gênante à propos de l'allocation de mémoire est l'objet String. En raison de sa nature particulière, de nombreux programmeurs sont sujets à la confusion. Je vais l'expliquer en détail dans le prochain article.