Principe de la compilation AOT

JEP 544 définit un cache AOT où le code natif d’une application est généré lors d’une exécution d’entraînement. Cette exécution utilise le même HotSpot que les runs de production, mais le profilage est conservé et le code natif optimisé est stocké dans le cache. Lors du lancement suivant, le JVM charge immédiatement ce code depuis le cache, éliminant ainsi l’interpréteur et les premières phases de compilation JIT. Le cache est valable uniquement pour la même architecture CPU (AArch64 ou x64) et les mêmes caractéristiques matérielles, ce qui exclut toute forme de cross‑compilation.

Intégration avec le pipeline JIT

Le processus AOT ne remplace pas le JIT ; il le complète. Au démarrage, les méthodes les plus fréquemment invoquées sont déjà présentes sous forme native grâce au cache AOT, tandis que le JIT continue d’observer le profil d’exécution. Si le profil évolue, HotSpot déoptimise les morceaux de code AOT devenus obsolètes et les remplace par du code JIT généré à la volée par les compilateurs C1 (baseline) puis C2 (optimisé). Cette transition est transparente pour l’application, conformément à l’objectif de ne pas introduire de nouveaux workflows AOT.

Contraintes d’architecture et de configuration

Le JEP précise que le cache AOT fonctionne uniquement avec les collecteurs de mémoire Serial, Parallel, G1 et ZGC, sans modification de configuration autre que l’activation du cache (option -XX:AOTCacheDir). Aucun changement de code source, de bibliothèque ou de framework n’est requis. Le support est limité aujourd’hui à AArch64 et x64 ; les autres architectures supportées par HotSpot seront ajoutées par les activités de portage classiques. Le cache ne constitue pas un mode « AOT‑only », il ne peut donc pas être utilisé pour des environnements où le JIT serait désactivé.

Impact sur les performances et limites

En pratique, le cache AOT réduit le temps de démarrage de plusieurs secondes pour les applications lourdes, car le code natif est disponible dès le premier appel de la méthode main. La phase de warm‑up est également raccourcie : les méthodes déjà optimisées par AOT ne nécessitent plus de compilation C1, ce qui libère du CPU et de la mémoire pendant les premiers instants d’exécution. Cependant, le gain dépend fortement de la similarité entre la charge de travail d’entraînement et celle de production ; un changement de profil entraîne une re‑optimisation JIT qui consomme les mêmes ressources que dans le modèle traditionnel. De plus, le cache AOT augmente la consommation d’espace disque proportionnel au nombre de méthodes compilées, et la génération du cache nécessite une exécution préalable complète, ce qui peut compliquer les pipelines CI/CD. Enfin, l’absence de support de cross‑compilation signifie que chaque plateforme de déploiement doit disposer de son propre cache, limitant les économies potentielles dans les environnements hétérogènes.