Dans les environnements de développement Java, les machines virtuelles jouent un rôle capital dans le lien entre les performances du code et de l’exécutable à travers toutes les machines. Ce sont des systèmes complexes qui sont au cœur de la gestion de l’exécution du code, de la mémoire et des ressources système. Une compréhension complète des JVM est donc essentielle pour les développeurs utilisant Java. Dans cet article, nous allons tâcher de comprendre l’architecture des JVM.
Vous souhaitez percer tous les secrets du langage de programmation ? Notre Formation Java en inter et intraentreprise vous permettra de maitriser complètement Java grâce à des connaissances théoriques et des mises en application pratiques.
L’équipe Ambient IT
Architecture des JVM
Les JVM sont conçues pour fournir un environnement d’exécution indépendant de la plateforme pour les applications Java. Elles comprennent de nombreux éléments techniques fonctionnant à l’unisson.
Sous-système Class Loader
C’est la fondation de l’architecture JVM. C’est ce composant qui gère le chargement des fichiers de classe. Dans Java, les classes ne sont pas toutes chargées dans l’application, elles le sont uniquement en cas de besoin. Cette fonctionnalité est essentielle dans la gestion de la mémoire dans Java.
Le processus peut être décomposé comme ceci :
- Loading : c’est la phase durant laquelle le chargeur de classes lit les données binaires d’un fichier de classe et les introduit dans la zone de données d’exécution.
- Linking : ce processus consiste en 3 autres sous-phases :
- Vérification : assure l’exactitude de la classe.
- Préparation : la JVM alloue de la mémoire aux variables de la classe.
- Résolution : transforme les références symboliques du type en références directes.
- Initialization : c’est la phase finale du chargement de la classe, au cours de laquelle la JVM attribue les valeurs initiales correctes aux champs statiques de la classe et exécute tous les blocs d’initialisation statiques.
Type de class loaders
Dans Java, les class loaders servent au chargement dynamique des classes au moment de l’exécution. Il existe plusieurs types de class loaders, chacun ayant une fonction spécifique dans l’environnement d’exécution :
- Bootstrap : parent de toutes les autres class loaders, il charge les bibliothèques Java de base située dans le répertoire /jre/lib, telles que rt.jar et d’autres bibliothèques de base. Implémenté en code natif plutôt qu’en Java.
- Extension : charge les classes qui sont une extension des classes Java standard.
- System/Application : charge les classes trouvées dans le chemin d’accès (classpath), qui peut être spécifié lors de l’exécution d’une application Java.
- User-Defined : ce sont des class loaders créés par les utilisateurs eux-mêmes. Ils sont généralement utilisés dans des applications complexes aux besoins spécifiques.
Zone de donnée d’exécution
Partie cruciale de la structure de la mémoire, elle est divisée en plusieurs parties :
- Zone Methods : ressource partagée entre tous les threads et qui stocke des structures par classe telles que le pool de constantes d’exécution, les données des champs et des méthodes, ainsi que le code des méthodes et des constructeurs.
- Zone de tas : également une ressource partagée, c’est à partir de cette zone que la mémoire de toutes les instances de classe et de tous les tableaux est allouée.
- Zone de pile : chaque thread dispose d’une pile JVM privée créée en même temps que le thread. Un cadre dans la pile contient des variables locales et des résultats partiels, et joue un rôle dans l’invocation et le retour des méthodes.
- Registre Program Counter : contient l’adresse de l’instruction JVM en cours d’exécution
- Pile Methods natives : contiens toutes les méthodes natives utilisées dans l’application.
Moteur d’exécution
C’est le composant qui exécute les instructions contenues dans les méthodes des classes. Comme tous les autres éléments de l’architecture Java, il se découpe en plusieurs éléments :
- Interprète : lis le flux bytecode.
- Compilateur Just-In-Time : compile le bytecode en code machine natif afin que l’unité centrale puisse l’exécuter directement.
- Collecteur de déchets : exécuté en arrière-plan, il supprime les objets qui ne sont plus utilisés, libérant ainsi des ressources mémoires.
Techniques d’optimisation du compilateur JIT
Le compilateur Compilateur Just-In-Time est un outil crucial dans les performances de votre environnement Java et il existe des techniques pour en optimiser le fonctionnement.
Inlining
Pour réduire la surcharge des appels de méthode, le compilateur JIT intègre souvent des méthodes inlining.
Optimisation des boucles
Ces optimisations réduisent la surcharge des boucles et améliorent les performances du cache.
Élimination du code mort
Supprimer le code qui n’affecte pas le résultat du programme (comme les variables inutilisées ou le code inaccessible) permet de réduire la taille du code et le temps d’exécution.
Recompilation dynamique
Également connue sous le nom d’optimisation adaptative. Cette méthode se base sur le compilateur JIT qui surveille l’exécution d’un programme et recompile les parties du code qui peuvent être optimisées en fonction du comportement de l’exécution. Cette approche permet d’optimiser les modèles d’utilisation réels de l’application.
Conclusion
L’architecture de la JVM est un système qui, bien que complexe, est parfaitement conçu pour garantir l’exécution sûre et efficace des applications Java sur différentes plates-formes. Il est essentiel de comprendre ses composants et leurs interactions pour optimiser les applications Java et tirer parti de toute la puissance de l’écosystème Java.