Jvmmemorymodel
Cet article présente principalement la zone de données d'exécution (RuntimedataaReas) décrite dans la spécification JVM. Ces zones sont conçues pour stocker les données utilisées par le JVM elle-même ou les programmes exécutés sur le JVM.
Présentons d'abord le JVM, puis introduisons le bytecode et introduisons enfin différentes zones de données.
Aperçu
En tant qu'abstraction du système d'exploitation, JVM garantit que le même code se comporte de manière cohérente sur différents systèmes de matériel ou d'exploitation.
Par exemple:
Pour le type de base INT, il s'agit d'un entier signé 32 bits, quel que soit le système d'exploitation 16 bits / 32 bits / 64 bits. Varie de -2 ^ 31 à 2 ^ 31-1
Peu importe que le système d'exploitation ou le matériel soit de l'ordre de plus grand ou petit octet, il est assuré que les données en mémoire stockées et utilisées par le JVM sont un ordre d'octets grand ou petit (lisez d'abord l'octet élevé) en premier)
Différentes implémentations JVM peuvent différer quelque peu, mais sont généralement les mêmes.
L'image ci-dessus est un aperçu d'un JVM
Le JVM interprète le bytecode généré par le compilateur. Bien que JVM soit l'abréviation des machines virtuelles Java, tant qu'il s'agit d'un langage qui peut être compilé en bytecode, il peut être exécuté en fonction du JVM, comme Scala, Groovy <� "/ kf / ware / VC /" Target = "_ Blank"> vcd4ncjxwps6qwcux3mpixrw3sbxetmxfzekvt6os19a92slru + gxu2nsyxnzbg9hzgvyvnpu2lkiu7q05r W91MVQ0MQXYV2 + 3CF41TC1XNK7UPBH + NPYO6ZWQRXAVNPU2MV8TCRJBGFZC2XVYWRLCRG7Z / Q72BVY1D9KVK3NO9A51MVQ0KGJPC 9WPG0KPHA + VNPU2LXE19A92SLRZAI5 / DA00NDS / CFMKGV4ZWN1DGLVBIBLBMDPBMUPVFJQ0L3IYS26ZDA00NA8L3A + DQO8CD7WT NDQ0V3H5TDO0QQ05RSIS8ZQ8SNPZ8LOXKOSSCJI57PM0PLWTNDQTB3EXNK70NCJRLVY1D / K / B7DVMBL47XE1TC85L3HUFS8L3A + D + D. QO8CD7WTNDQ0V3H5TKYULRU8LSMWO3T67XXSUOY2DF3Z7XNS7XEVBU7PTWVCD4NCJXWPIOQUTY24EPWTBA8YRXP1SHLVLTKSBHG 0UU5PSTCKEPJVD1QDXN0IGLUIHRPBWUPOANKSVS + ZCRHSNG + RBOJ1RTQ0LXETPRC6YJIYLXJTPRC6YMX4NLRS8MXVRXYTPRC6YHO YxrpdMUGQ29KZSMHO7TMT8VKSVSX4NLRYFQZYBT6WUU1XMF40 / KZXS6QPC9WPG0KPHA + TPRC67U6TOBH + CHDB2RLIENH Y2GPOAO8TMQXSEDS67Y8YVUOSKLUKBY2TPO1XMZHUN / BY0PWTBXE0NTE3COQPC9WPG0KPGGYIGLKPQ == "Stack-basez Architecture "> Architecture basée sur la pile
JVM utilise une architecture basée sur la pile. Bien que la pile soit transparente pour les développeurs, elle a un rôle ou une influence très important sur le bytecode généré et le JVM.
Les programmes que nous avons développés convertiront les opérations de bas niveau et les stockeront dans ByteCode. Carte aux instructions de fonctionnement via les opérandes dans le JVM. Selon la spécification JVM, les paramètres requis par les instructions de fonctionnement sont obtenus à partir de la pile d'opérande.
Donnons un exemple d'ajout de deux nombres. Cette opération est appelée IADD. Ce qui suit est le processus de 3 + 4 en bytecode
Première poussée 3 et 4 dans la pile d'opérande
Appelez la directive IADD
L'instruction IADD apparaît 2 numéros du haut de la pile d'opérande
Le résultat de 3 + 4 est poussé dans la pile d'opérande pour une utilisation ultérieure
Cette approche est appelée une architecture basée sur la pile. Il existe d'autres moyens de gérer les opérations de bas niveau, telles que l'architecture basée sur le registre.
Bytecode
Java bytecode est le résultat de la conversion du code source Java en une série d'opérations de bas niveau. Chaque opération se compose d'un code d'opcode ou d'opération avec des paramètres de longueur de zéro ou plus d'octets (mais la plupart des opérations utilisent des paramètres obtenus via la pile d'opérande). Un octet peut représenter 256 numéros, de 0x00 à 0xFF, et actuellement à Java8, un total de 204 sont utilisés.
Le suivant répertorie différents types d'opcodes ByteCode, ainsi que leur gamme et leur description simple
Constantes: poussez la valeur du pool constant ou une valeur connue dans la pile d'opérande. 0x00 - 0x14
Charges: poussez les valeurs de variables locales dans la pile de l'opérande. 0x15 - 0x35
Stores: Valeur de chargement de la pile d'opérande à la variable locale 0x36 - 0x56
Stack: Process Operand Stack 0x57 - 0x5f
Math: Obtenez la valeur de la pile de l'opérande pour le calcul mathématique de base 0x60 - 0x84
Conversions: Convertissez entre les types 0x85 - 0x 93
Comaprisons: fonctionnement de comparaison de deux valeurs 0x94 - 0xa6
Contrôles: Exécutez Goto, Return, Loop, etc. Opérations de contrôle 0xa7 - 0xb1
Références: exécute des objets ou des tableaux d'allocation, et obtient ou vérifie les références aux objets, aux méthodes et aux méthodes statiques. Les méthodes statiques peuvent également être appelées. 0xb2 - OXC3
Extension: étendu: opérations des autres catégories qui ont été ajoutées après. De la valeur 0xc4 à 0xc9
(Que signifie cette phrase?
Réservé: L'implémentation JVM utilise des emplacements 0xca, Oxfe, OXFF
Ces 204 opérations sont très simples, donnent quelques exemples
IFEQ (0x99) détermine si les deux valeurs sont égales
IADD (0x60) ajoute deux nombres
I2L (0x85) convertit un peu long
ArrayLength (0xbe) renvoie la longueur du tableau
pop (0x57) Pop une valeur du haut de la pile d'opérande
Nous avons besoin d'un compilateur pour créer des fichiers bytecode, et le compilateur Java standard est Javac dans JDK.
classe publique test {public static void main (String [] args) {int a = 1; int b = 15; INT Result = Add (a, b); } public static int add (int a, int b) {int result = a + b; Résultat de retour; }}Vous pouvez obtenir le fichier bytecode de "test.class" via "javac test.java". Les fichiers bytecode sont binaires, nous pouvons convertir les fichiers binaires binaires en formulaire de texte via Javap
Java -Verbose Test.class
Classfile /c:/tmp/test.class Last Modified 1 Avr. 2015; Taille 367 octets MD5 Checksum Adb9ff75f12fc6ce1cdde22a9c4c7426 compilé à partir de "test.java" Classe publique com.codinggeek.jvm.Test Sourcefile: "test.java" Version mineure: 0 version majeure: 51 Flags: ACC_PUBLIC, ACC_SUPERCO java / lang / objet. "<init>" :() v # 2 = méthodeRef # 3. # 16 // com / codinggeek / jvm / test.add: (ii) i # 3 = classe # 17 // com / codinggeek / jvm / test # 4 = classe # 18 // java / lang / objet # 5 = utf8 <init> # 6 = utf8 () v # 7 = objet # 5 = utf8 <init> # 6 = utf LineNumberTable # 9 = UTF8 Main # 10 = UTF8 ([Ljava / Lang / String;) V # 11 = UTF8 Add # 12 = UTF8 (II) I # 13 = UTF8 SourceFile # 14 = UTF8 Test.Java # 15 = NAMEAndTYPE # 5: # 6 // "<init>" :() V # 16 = NAMEANDTYPE # 11: # 12 / ") # 17 = UTF8 COM / CODINGGEEK / JVM / TEST # 18 = UTF8 Java / Lang / Object {public com.codinggeek.jvm.test (); Flags: ACC_PUBLIC CODE: Stack = 1, Locals = 1, args_size = 1 0: Aload_0 1: InvokeSpecial # 1 // Method Java / Lang / Object. "<init>" :() V 4: return lineNumberTable: Line 3: 0 public static void Main (java.lang.string []); Flags: ACC_PUBLIC, ACC_STATIC CODE: Stack = 2, Locals = 4, Args_Size = 1 0: iConst_1 1: istore_1 2: Bipush 15 4: Istore_2 5: Iload_1 6: Iload_2 7: Invikestatic # 2 // Méthode Ajouter: (II) 5 Ligne 9: 11 public static int Add (int, int); Flags: ACC_PUBLIC, ACC_STATIC CODE: Stack = 2, Locals = 3, Args_Size = 2 0: Iload_0 1: Iload_1 2: IADD 3: Istore_2 4: Iload_2 5: Ireturn LineNumberTable: Line 12: 0 Ligne 13: 4}On peut voir que ByteCode n'est pas seulement une simple traduction du code Java, il comprend:
Une description constante du pool de la classe. Les pools constants sont des zones de données JVM utilisées pour stocker les métadonnées de classe, telles que les noms de méthode, les listes de paramètres, etc. à l'intérieur de la classe. Lorsque le JVM charge une classe, les métadonnées seront chargées dans le pool constant
Fournissez les informations de position spécifiques des fonctions et des variables TMALL dans ByteCode via la table de numéro de ligne et la table variable locale.
Traduction du code Java (y compris les constructions de classe parents cachées)
Fournit des opérations plus spécifiques sur les piles d'opérande et des moyens plus complets de passer et d'obtenir des paramètres
Vous trouverez ci-dessous une description simple des informations de stockage de fichiers bytecode
ClassFile {U4 Magic; U2 Minor_version; U2 Major_version; U2 constant_pool_count; cp_info constant_pool [constant_pool_count-1]; u2 Access_Flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces [interfaces_count]; U2 Fields_Count; field_info fields [fields_count]; u2 attributs_count; attribut_info attributs [attributs_count];}Zone de données d'exécution
La zone de données d'exécution est la zone de mémoire conçue pour stocker les données. Ces données sont utilisées par les développeurs ou JVM en interne.
Tas
Le tas est créé lorsque le JVM est démarré et partagé par tous les threads JVM. Toutes les instances et tableaux de classe sont alloués au tas (créé par New).
Le tas doit être géré par un collecteur de déchets, qui est responsable de la libération d'objets créés par le développeur et ne sera plus utilisé.
Quant à la stratégie de collecte des ordures, il est déterminé par l'implémentation JVM (par exemple, Hotspot fournit plusieurs algorithmes).
Il y a une limite maximale pour la mémoire du tas. Si cette valeur est dépassée, le JVM lancera une exception OutOfMemroy.
Zone de méthode
La zone de méthode est également partagée par tous les fils de la JVM. La même chose est créée avec le démarrage JVM. Les données stockées dans la zone de la méthode sont chargées à partir du bytecode par le Classloader, qui existera de manière cohérente pendant l'exécution de l'application, à moins que le chargeur de classe de les charger est détruit ou que le JVM soit arrêté.
La zone de méthode stocke les données suivantes:
Informations de classe (nom d'attribut, nom de méthode, nom de classe parent, nom d'excuse, version, etc.)
Méthodes et codes deytecodes construits
Pool constant d'exécution créé lors du chargement de chaque classe
La spécification JVM ne force pas les zones de méthode à implémenter dans le tas. Avant Java7, les zones de méthode implémentées par hotspot utilisant une région appelée permgen. La bande permanente est adjacente au tas (la gestion de la mémoire est la même que le tas), le bit par défaut est de 64 Mo
À partir de Java8, HPTSPOT utilise une mémoire locale distincte pour implémenter la zone de méthode et nommer la zone de métadonnées (Metaspace). L'espace disponible maximal dans la zone des métadonnées est la mémoire disponible de l'ensemble du système.
Si la méthode ne peut pas s'appliquer pour la mémoire disponible, le JVM lancera également OutOfMemoryError.
Pool de runtime constant
Le pool constant d'exécution fait partie de la zone de méthode. En raison de l'importance de faire fonctionner un pool constant pour les métadonnées, il est décrit séparément dans la spécification Java en dehors de la zone de la méthode. Le pool constant d'exécution se développe avec les classes et les interfaces chargées.
Les pools constants sont un peu une table de syntaxe dans les langues traditionnelles. En d'autres termes, lorsqu'une classe, méthode ou propriété est appelée, le JVM recherche l'adresse réelle de ces données en mémoire via le pool constant d'exécution. La piscine constante d'exécution contient également des constantes de littéraux de cordes ou de types primitifs
Stirng myString = "Ceci est une chaîne Litteral" statique final int my_constant = 2;
PC (compteur de programme) Registre (par thread) Le registre PC (par thread)
Chaque thread a son propre registre PC (Counter Counter), qui est créé avec la création de threads. Chaque thread ne peut exécuter qu'une seule méthode à un point, appelé la méthode actuelle du thread. Le registre PC contient l'adresse de la JVM en exécutant actuellement l'instruction (dans la zone de méthode).
Si la méthode actuellement exécutée est une méthode locale, la valeur du registre PC n'est pas définie
Pile de machines virtuelles par thread-java-virtual-machine stacks par thread "> pile de machine virtuelle (par thread) piles de machines virtuelles Java (par thread)
La pile virtuelle Machine stocke plusieurs images, donc avant de décrire la pile, jetons un coup d'œil aux cadres en premier.
Cadres
Un cadre est une structure de données qui contient plusieurs données représentant l'état de méthode actuelle que le thread s'exécute:
Pile d'opérande: Comme mentionné précédemment, les instructions Bytecode utilisent la pile d'opérande pour passer les paramètres
Tableau de variables locales: ce tableau contient toutes les variables locales dans la portée de la méthode actuellement exécutée. Ce tableau peut contenir un type primitif, une référence ou une adresse de retour. La taille du réseau variable local est déterminée au temps de compilation. JVM utilise des variables locales pour transmettre des paramètres lors de l'appel de la méthode, et le tableau variable local de la méthode appelée est créé via la pile d'opérande de la méthode d'appel.
Référence du pool constant d'exécution: références au pool constant de la méthode actuelle de la classe actuelle. Le JVM utilise des références de pool constantes aux signaux de passe aux références de mémoire réelles.
Pile (pile)
Chaque fil JVM a une pile JVM privée, qui est créée en même temps que le fil. Java Virtual Machine Stack stocke les cadres. Chaque fois qu'une méthode est appelée, un cadre est créé et poussé dans la pile de machine virtuelle. Lorsque cette méthode est exécutée, le cadre sera également détruit (que la méthode soit exécutée normalement ou une exception est lancée)
Une seule trame est disponible lors de l'exécution d'un fil. Ce cadre est appelé le cadre actuel.
Les opérations sur les variables locales et les piles d'opérande sont généralement accompagnées de références à la trame actuelle.
Regardons un autre exemple d'addition
public int Add (int a, int b) {return a + b;} public void functiona () {// un code sans fonction appelle introduction = add (2,3); // Appel à la fonction b // du code sans fonction appelez-vous}À l'intérieur de la méthode A, le cadre A est le cadre actuel, situé en haut de la pile de machine virtuelle. Au début de l'appel de la méthode ADD, un nouveau cadre B est créé et poussé dans la pile de machines virtuelles. Le cadre B devient le nouveau cadre actuel.
Le tableau variable local du cadre B est rempli de données dans la pile d'opérande du cadre A. Lorsque la méthode ADD se termine, le cadre B est détruit et le cadre A est rétabli en tant que cadre actuel. Le résultat de la méthode ADD est poussé dans la pile d'opérande de la trame A, de sorte que la méthode A peut obtenir le résultat de l'ajout via la pile d'opérande du cadre A.
Résumer
Ce qui précède concerne l'analyse de la zone de données de l'exécution de la machine virtuelle Java. J'espère que ce sera utile à tout le monde.
S'il y a des lacunes, veuillez laisser un message pour le signaler.