logo

Comment fonctionne la JVM – Architecture JVM ?

JVM (Java Virtual Machine) agit comme un moteur d'exécution pour exécuter des applications Java. La JVM est celle qui appelle réellement le principal méthode présente dans un code Java. JVM fait partie de JRE (Java Runtime Environment).

Les applications Java sont appelées WORA (Write Once Run Anywhere). Cela signifie qu'un programmeur peut développer du code Java sur un système et s'attendre à ce qu'il s'exécute sur n'importe quel autre système compatible Java sans aucun ajustement. Tout cela est possible grâce à JVM.

Quand on compile un .Java déposer, .classe fichiers (contient du byte-code) avec les mêmes noms de classe présents dans .Java Le fichier est généré par le compilateur Java. Ce .classe Le fichier passe par différentes étapes lorsque nous l'exécutons. Ces étapes décrivent ensemble l’ensemble de la JVM.



jvm


Sous-système de chargement de classe

Il est principalement responsable de trois activités.

  • Chargement
  • Mise en relation
  • Initialisation

Chargement: Le chargeur de classe lit le fichier . classe fichier, générez les données binaires correspondantes et enregistrez-les dans la zone méthode. Pour chaque .classe , JVM stocke les informations suivantes dans la zone méthode.

  • Le nom complet de la classe chargée et de sa classe parent immédiate.
  • Si le .classe Le fichier est lié à la classe, à l'interface ou à l'énumération.
  • Informations sur le modificateur, les variables et la méthode, etc.

Après avoir chargé le .classe fichier, JVM crée un objet de type Class pour représenter ce fichier dans la mémoire tas. Veuillez noter que cet objet est de type Classe prédéfinie dans java.lang emballer. Ces objets Class peuvent être utilisés par le programmeur pour obtenir des informations au niveau de la classe telles que le nom de la classe, le nom du parent, les méthodes et les informations sur les variables, etc. Pour obtenir cette référence d'objet, nous pouvons utiliser getClass() méthode de Objet classe.

Java

CSS centrant une image




// A Java program to demonstrate working> // of a Class type object created by JVM> // to represent .class file in memory.> import> java.lang.reflect.Field;> import> java.lang.reflect.Method;> // Java code to demonstrate use> // of Class object created by JVM> public> class> Test {> >public> static> void> main(String[] args)> >{> >Student s1 =>new> Student();> >// Getting hold of Class> >// object created by JVM.> >Class c1 = s1.getClass();> >// Printing type of object using c1.> >System.out.println(c1.getName());> >// getting all methods in an array> >Method m[] = c1.getDeclaredMethods();> >for> (Method method : m)> >System.out.println(method.getName());> >// getting all fields in an array> >Field f[] = c1.getDeclaredFields();> >for> (Field field : f)> >System.out.println(field.getName());> >}> }> // A sample class whose information> // is fetched above using its Class object.> class> Student {> >private> String name;> >private> int> roll_No;> >public> String getName() {>return> name; }> >public> void> setName(String name) {>this>.name = name; }> >public> int> getRoll_no() {>return> roll_No; }> >public> void> setRoll_no(>int> roll_no)> >{> >this>.roll_No = roll_no;> >}> }>

>

>

Sortir

Student getName setName getRoll_no setRoll_no name roll_No>

Note: Pour chaque chargé .classe fichier, seulement un l'objet de la classe est créé.

Student s2 = new Student(); // c2 will point to same object where  // c1 is pointing Class c2 = s2.getClass(); System.out.println(c1==c2); // true>

Mise en relation: Effectue la vérification, la préparation et (éventuellement) la résolution.

  • Vérification : Il garantit l'exactitude du .classe c'est-à-dire qu'il vérifie si ce fichier est correctement formaté et généré par un compilateur valide ou non. Si la vérification échoue, nous obtenons une exception d'exécution java.lang.VerifyError . Cette activité est réalisée par le composant ByteCodeVerifier. Une fois cette activité terminée, le fichier de classe est prêt à être compilé.
  • Préparation : JVM alloue de la mémoire pour les variables statiques de classe et initialise la mémoire aux valeurs par défaut.
  • Résolution : C'est le processus de remplacement des références symboliques du type par des références directes. Cela se fait en recherchant dans la zone de méthode pour localiser l'entité référencée.

Initialisation : Dans cette phase, toutes les variables statiques sont affectées avec leurs valeurs définies dans le code et le bloc statique (le cas échéant). Ceci est exécuté de haut en bas dans une classe et de parent à enfant dans la hiérarchie des classes.
En général, il existe trois chargeurs de classes :

  • Chargeur de classe Bootstrap : Chaque implémentation JVM doit disposer d'un chargeur de classe d'amorçage, capable de charger des classes de confiance. Il charge les classes principales de l'API Java présentes dans le JAVA_HOME/jre/lib annuaire. Ce chemin est communément appelé chemin d’amorçage. Il est implémenté dans des langages natifs comme C, C++.
  • Chargeur de classe d'extension : C'est un enfant du chargeur de classe bootstrap. Il charge les classes présentes dans les répertoires d'extensions JAVA_HOME/jre/lib/ext (Chemin d'extension) ou tout autre répertoire spécifié par la propriété système java.ext.dirs. Il est implémenté en Java par le sun.misc.Launcher$ExtClassLoader classe.
  • Chargeur de classe système/application : C'est un enfant du chargeur de classe d'extension. Il est responsable du chargement des classes à partir du chemin de classe de l'application. Il utilise en interne une variable d'environnement mappée à java.class.path. Il est également implémenté en Java par le sun.misc.Launcher$AppClassLoader classe.

Java


long à enfiler



// Java code to demonstrate Class Loader subsystem> public> class> Test {> >public> static> void> main(String[] args)> >{> >// String class is loaded by bootstrap loader, and> >// bootstrap loader is not Java object, hence null> >System.out.println(String.>class>.getClassLoader());> >// Test class is loaded by Application loader> >System.out.println(Test.>class>.getClassLoader());> >}> }>

>

>

Sortir

null jdk.internal.loader.ClassLoaders$AppClassLoader@8bcc55f>

Note: JVM suit le principe de délégation-hiérarchie pour charger les classes. Le chargeur de classe système délègue la demande de chargement au chargeur de classe d'extension et le chargeur de classe d'extension délègue la demande au chargeur de classe d'amorçage. Si une classe est trouvée dans le chemin de démarrage, la classe est chargée, sinon elle demande à nouveau d'être transférée au chargeur de classe d'extension, puis au chargeur de classe système. Enfin, si le chargeur de classe système ne parvient pas à charger la classe, nous obtenons une exception d'exécution. java.lang.ClassNotFoundException .

jvm

Mémoire JVM

  1. Domaine méthode : Dans la zone des méthodes, toutes les informations au niveau de la classe telles que le nom de la classe, le nom de la classe parent immédiat, les informations sur les méthodes et les variables, etc. sont stockées, y compris les variables statiques. Il n'y a qu'une seule zone de méthode par JVM et il s'agit d'une ressource partagée.
  2. Zone de tas : Les informations de tous les objets sont stockées dans la zone de tas. Il existe également une zone de tas par JVM. C'est aussi une ressource partagée.
  3. Zone de pile : Pour chaque thread, JVM crée une pile d'exécution qui est stockée ici. Chaque bloc de cette pile est appelé enregistrement d'activation/cadre de pile qui stocke les appels de méthodes. Toutes les variables locales de cette méthode sont stockées dans leur frame correspondant. Une fois qu'un thread se termine, sa pile d'exécution sera détruite par JVM. Ce n'est pas une ressource partagée.
  4. Registres PC : Stocke l’adresse de l’instruction d’exécution actuelle d’un thread. Évidemment, chaque thread possède des registres PC distincts.
  5. Piles de méthodes natives : Pour chaque thread, une pile native distincte est créée. Il stocke les informations sur la méthode native.

jvm2

Moteur d'exécution

Le moteur d'exécution exécute le .classe (bytecode). Il lit le byte-code ligne par ligne, utilise les données et informations présentes dans diverses zones mémoire et exécute les instructions. On peut le classer en trois parties :

  • Interprète : Il interprète le bytecode ligne par ligne puis s'exécute. L’inconvénient ici est que lorsqu’une méthode est appelée plusieurs fois, une interprétation est requise à chaque fois.
  • Compilateur juste à temps (JIT) : Il est utilisé pour augmenter l’efficacité d’un interprète. Il compile l'intégralité du bytecode et le modifie en code natif. Ainsi, chaque fois que l'interpréteur voit des appels de méthode répétés, JIT fournit du code natif direct pour cette partie, de sorte qu'une réinterprétation n'est pas nécessaire, ce qui améliore l'efficacité.
  • Éboueur : Il détruit les objets non référencés. Pour en savoir plus sur Garbage Collector, reportez-vous Éboueur .

Interface native Java (JNI) :

C'est une interface qui interagit avec les bibliothèques de méthodes natives et fournit les bibliothèques natives (C, C++) nécessaires à l'exécution. Il permet à JVM d'appeler des bibliothèques C/C++ et d'être appelée par des bibliothèques C/C++ qui peuvent être spécifiques au matériel.

Structure de données

Bibliothèques de méthodes natives :

Il s'agit d'une collection de bibliothèques natives (C, C++) requises par le moteur d'exécution.