luchschen_shutter - Fotolia

Java 25 : Oracle vante les gains de performance

Si la précédente version de l’OpenJDK était axée sur l’IA et le chiffrement postquantique, Oracle évoque pour cette édition supportée à long terme les gains obtenus grâce aux évolutions des projets lancés après Java 9.

Retour aux choses sérieuses. Java 25 arrive en disponibilité générale. Cette version supportée à long terme (deux ans de support commercial, huit ans au total) du framework fait suite à une édition 24 plutôt copieuse avec… 24 ajouts notables. Les porte-parole d’Oracle avaient déjà indiqué que l’OpenJDK 25 ne comporterait pas autant d’améliorations (Java Enhanced Proposals ou JEPs). Le fournisseur et la communauté y ont tout de même glissé 18 JEPs, un peu plus qu’anticipé. Il y a surtout plus de 3000 corrections de bugs, de vulnérabilité et d’amélioration de bas niveau.

« On a vraiment l’impression qu’il y a une renaissance de Java et que le pipeline d’innovations est plus riche que jamais », vante Chad Arimura, vice-président des relations avec les développeurs Java chez Oracle.

Il faut dire que depuis le lancement des grands projets de modernisation et le changement de cycle de mise à jour (OpenJDK 9), Java gagne doucement, mais sûrement des points pour perdurer dans le cloud, même après 30 ans d’existence.

Si Java 24 a été lancé sous le signe de l’IA et du chiffrement postquantique, l’arrivée d’une version LTS remet les pendules à l’heure. Non pas que la communauté mette de côté les innovations ou les facilités pour les jeunes développeurs. La plupart des simplifications du langage présentées il y a six mois sont désormais standards. L’implémentation des objets associés au chiffrement postquantique se poursuit (notamment l'intégration à TLS 1.3). Tout comme le projet Babylon – censé simplifier l’interopérabilité avec les GPU et donc permettre des cas d’usage liés à l’IA.

 Toutefois, les avantages principaux de l’OpenJDK 25 se trouvent du côté des performances. Neuf des dix-huit JEPs concernent ce sujet. Sept d’entre elles sont en « disponibilité générale ».

Moins de pauses dans la collecte de déchets

Ces optimisations ciblent d’abord la collection de déchets. Pour rappel, ZGC est devenu le collecteur par défaut depuis Java 23.

« ZGC permet d’obtenir des temps de pause inférieurs à la milliseconde dans des heap très volumineux », assure Chad Arimura. « Il s’agit donc d’une option parmi les nombreux collecteurs de déchets qui font partie du JDK. Mais elle gagne en popularité à mesure que nous continuons à l’améliorer ».

C’est l’objet de la JEP 519 qui optimise les en-têtes d’objet compact. La fonctionnalité était en version expérimentale dans l’OpenJDK 24. Il se trouve qu’Amazon a pu la tester en production dans des centaines de services.

Sur le benchmark SPECjbb2015, ZGC composerait 22 % moins d’espace heap et moins 8 % de temps CPU. En moyenne, les améliorations baisseraient d’environ 15 % le nombre de tâches de collecte de déchets.

Si ZGC est désormais le « garbage collector » par défaut, d’autres GC continuent d’évoluer. C’est le cas de Generation Shenandoah (JEP 521) qui a gagné en efficacité depuis Java 24 et a lui testé à large échelle.

Le temps de démarrage des applications Java de plus en plus court

L’autre volet important concerne la compilation « ahead of time » (anticipée). Ce sujet, remis sur la table en 2019, est lié au projet Leyden. « Leyden concerne le temps de démarrage », résume Chad Arimura. « Il s’agit donc de lancer des applications, par exemple dans des conteneurs ou des environnements serverless où vous souhaitez qu’elles démarrent très rapidement, puis s’arrêtent à la même cadence », ajoute-t-il. « Vous ne pouvez pas attendre une minute et demie pour qu’elles démarrent si vous disposez de 15 secondes de temps de traitement ».

La JEP 514 doit simplifier la création de zones de cache par l’apport d’une ligne de commande qui ne nécessite plus des expressions divisées en plusieurs étapes. À ce moment-là, l’unique ligne de commande est associée à un fichier temporaire créé par la JVM (Java Virtual Machine) pour la configuration de la compilation AOT. Ce fichier est supprimé après l’exécution. Une variable d’environnement permet de transmettre des options de gestion de ce cache.

Cette fonction de cache est couplée à la JEP 515. « Le profilage des méthodes d’exécution » prend les précédents états d’une application qui a déjà été exécutée et les charge au démarrage de la VM Java Hotspot. « Cela permet au compilateur JIT (Just-In-Time) de générer du code natif immédiatement au démarrage de l’application, plutôt que d’avoir à attendre que les profils soient collectés », dixit la page associée.

Encore du travail en matière de concurrence des threads

Puis, il y a le projet Loom. « Il introduit ce qu’on appelle les threads virtuels, qui sont des threads légers permettant de créer un thread par requête, jusqu’à plusieurs millions », indique Chad Arimura. Concernant ce volet, la concurrence structurée (JEP 505) entre dans sa cinquième phase de préversion. Celle-ci permet de traiter des groupes de tâches associées s’exécutant dans différents threads comme une seule unité. Ce faisant, les risques d’annulation, d’arrêt et de fuites sont limités.

En outre, les valeurs à portée définie (JEP 506) offrent un mécanisme de partage de données immuables entre une méthode et les méthodes qu’elle appelle dans un thread ainsi qu’à travers les threads enfants. Elles sont vouées à remplacer les variables ThreadLocal, en particulier dans les usages de la concurrence dans des frameworks Java.

L’observabilité de Java, plus simple et plus précise

Pour la supervision des performances, la communauté revoit JDK Flight Recorder (JFR). « C’est un outil de monitoring très léger pour superviser vos applications », rappelle Chad Arimura.

La JEP 518 vise à améliorer sa stabilité au moment d’échantillonner des données en provenance de piles de threads d’un programme Java.

« Afin de produire une trace de pile pour un thread de programme, le thread échantillonneur de JFR doit suspendre le thread cible et analyser les frames d’appel dans la pile », expliquent les contributeurs. « La JVM HotSpot conserve des métadonnées pour guider l’analyse des frames de pile, mais ces métadonnées ne sont valides que lorsqu’un thread est suspendu à des emplacements de code bien définis appelés “points de sécurité” (safepoints) », poursuivent-ils. « Cependant, si nous échantillonnons les piles uniquement aux points de sécurité, nous risquons de souffrir du problème de biais de safepoints ». Ce problème bien connu des développeurs Java se manifeste quand un segment de code fréquemment exécuté ne se trouve pas à proximité d’un safepoint. Ils s’exposent à une perte de précision.

Pour éviter ce problème, la JEP 518 introduit un mécanisme d’échantillonnage asynchrone et « coopératif ».

L’échantillonneur optimise le processus en ne capturant que le compteur de programme et le pointeur de pile du thread cible, qu’il place dans une file d’attente locale. Le thread poursuit son exécution jusqu’à atteindre un safepoint. Le gestionnaire examine alors la file d’attente. Si des demandes d’échantillonnage sont présentes, il reconstruit les traces de pile en ajustant le biais du point de sécurité, puis émet un événement d’échantillonnage au temps d’exécution JFR.

Cela réduirait le biais évoqué plus haut, optimiserait le thread d’échantillonnage et permettrait aussi la création d’échantillons en réponse à un événement hardware.

La JEP 520, elle, concerne l’invocation de méthodes d’horodatage et de traçage via de l’instrumentation de bytecode (intermédiaire entre les instructions-machine et le code source).

Celles-ci doivent permettre d’identifier les goulets d’étranglement, les causes profondes d’un bug et d’optimiser le code. Les invocations étaient jusqu’alors peu satisfaisantes, complexes ou partielles. Ici, deux événements liés à l’outil de monitoring, ainsi qu’un lot de filtres, permettent d’obtenir facilement les données attendues.

Cette fois-ci dans un mode expérimental, la JEP 509 doit permettre de collecter des informations plus précises sur la consommation de cycles CPU par thread d’un programme Java s’exécutant sur un système d’exploitation Linux. Ce mécanisme est une application directe de la JEP 518.

Selon Oracle, l’ensemble des améliorations permettrait d’obtenir un gain de performance de 72 % avec le framework de microservices Helidon entre Java 21 et Java 25, « sans changement de code ». Oracle ne rapporte pas les résultats d’autres frameworks similaires (Quarkus, Spring Boot et d’autres), mais travaillerait avec les membres de communauté pour s’assurer que les optimisations ne créent pas de problème d’interopérabilité. Aux développeurs de vérifier les promesses de l’éditeur.

 

Pour approfondir sur Langages