Le compilateur JIT

Le compilateur JIT (Just-In-Time) est un composant de l'environnement d'exécution qui améliore les performances des applications Java™ en compilant des bytecodes en code machine natif lors de l'exécution.

Les programmes Java sont constitués de classes qui contiennent des bytecodes indépendants de la plateforme qui peuvent être interprétés par une machine virtuelle Java sur de nombreuses architectures d'ordinateur différentes. Lors de l'exécution, la JVM charge les fichiers de classe, détermine la sémantique de chaque bytecode et exécute les calculs appropriés. L'utilisation supplémentaire du processeur et de la mémoire lors de l'interprétation signifie qu'une application Java fonctionne plus lentement qu'une application native. Le compilateur JIT permet d'améliorer les performances des programmes Java en compilant les bytecodes en code machine natif lors de l'exécution.

Le compilateur JIT est actif par défaut. Dès lors qu'une méthode a été compilée, la JVM appelle directement son code compilé au lieu de l'interpréter. Théoriquement, si la compilation ne nécessite pas de temps processeur et d'utilisation de la mémoire, la compilation de chaque méthode peut permettre au programme Java de s'adapter à la vitesse d'une application native.

Or la compilation JIT consomme du temps processeur et de la mémoire. Au démarrage de la JVM, des milliers de méthodes sont appelées. La compilation de toutes ces méthodes peut affecter sensiblement le temps de démarrage du programme, qui une fois lancé, réalise néanmoins de très bonnes pointes de performances.

Dans la pratique, les méthodes ne sont pas compilées lorsqu'elles sont appelées la première fois. Pour chaque méthode, la JVM tient à jour un décompte des appels, qui commence à un seuil prédéfini et est décrémenté à chaque nouvel appel de la méthode. Lorsque ce décompte arrive à zéro, une compilation JIT est déclenchée pour la méthode. Par conséquent, les méthodes fréquemment utilisées sont compilées tôt après le démarrage de la JVM et les méthodes qui le sont moins, beaucoup plus longtemps après ou pas du tout. Le seuil de compilation JIT permet à la JVM de démarrer rapidement tout en réalisant de meilleures performances. La valeur de ce seuil a été choisi pour obtenir un équilibre optimal entre temps de démarrage et performances à long terme.

Le compilateur JIT peut compiler une méthode à différents niveaux d'optimisation: cold, warm, hot, veryHotou scorching (voir optlevel dans -Xjit). Les niveaux les plus hauts sont censés procurer de meilleures performances, mais ils sont aussi plus coûteux en utilisation de temps processeur et de mémoire. Le niveau d'optimisation appliqué initialement ou par défaut à une méthode est warm, mais il arrive que les heuristiques JIT rétrogradent la méthode au niveau cold pour améliorer le temps de démarrage.

Une méthode peut être recompilée à un niveau plus haut d'optimisation par différents mécanismes. L'un de ces mécanismes est l'échantillonnage: le compilateur JIT gère une unité d'exécution d'échantillonnage dédiée qui se réveille périodiquement et détermine les méthodes Java qui apparaissent plus souvent en haut de la pile. Considérées comme les plus importantes pour les performances, ces méthodes sont éligibles à une réoptimisation à l'un des niveaux plus hauts hot, veryHot ou scorching.

Vous pouvez désactiver le compilateur JIT, auquel cas l'ensemble du programme Java sera interprété. Il est recommandé de ne pas désactiver le compilateur JIT, sauf à des fins de diagnostic ou pour contourner les problèmes de compilation JIT.