IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

JDK 18, l'implémentation de référence de Java 18, est désormais disponible,
Elle propose comme Python, Ruby, PHP ou encore Erlang, un mini serveur Web prêt à l'emploi

Le , par Bruno

437PARTAGES

12  0 
Oracle Technologie a annoncé le 22 mars la sortie de la version 18 de JDK, l'implémentation de référence de Java 18, elle arrive avec un serveur web amélioré, une réimplémentation de Core Reflection avec des gestionnaires de méthode, une amélioration du SPI de résolution des adresses Internet et bien plus. « JDK 18, l'implémentation de référence de Java 18, est maintenant en disponibilité general (GA). Nous avons livré la build 36 en tant que première Release Candidate du JDK 18 le 15 février, et aucun bogue n'a été signalé. La build 36 est donc maintenant la build GA, prête à être utilisée en production », a déclaré Mark Reinhold, Architecte en chef, Java Platform au Groupe Oracle.

En fin d’année dernière, l'équipe Java Platform au Groupe Oracle a livré une Preview des nouveautés du JDK 18. Aujourd’hui, Java 18 est livré avec une API pour les vecteurs, un deuxième aperçu de la correspondance des motifs pour les instructions switch, l'UTF-8 comme jeu de caractères par défaut et d'un serveur Web minimal.

Réimplémentation de Core Reflection avec des gestionnaires de méthode

La réflexion de base a deux mécanismes internes pour invoquer les méthodes et les constructeurs. Pour un démarrage rapide, il utilise les méthodes natives de la VM HotSpot pour les premières invocations d'une méthode réflective spécifique ou d'un objet constructeur. Pour une meilleure performance maximale, après un certain nombre d'invocations, il génère du bytecode pour l'opération de réflexion et l'utilise lors des invocations suivantes.


Réimplémente les éléments java.lang.reflect.Method, Constructor et Field sur les gestionnaires de méthode java.lang.invoke. En faisant des gestionnaires de méthodes le mécanisme sous-jacent de la réflexion, les developpeurs reduisent les coûts de maintenance et de développement des API java.lang.reflect et java.lang.invoke.

Pour l'accès aux champs, la réflexion de base utilise l'API interne sun.misc.Unsafe. Avec l'API java.lang.invoke method-handle introduite dans Java 7, il existe en tout trois mécanismes internes différents pour les opérations de réflexion :

  • les méthodes natives VM ;
  • les gestionnaires de méthode ;
  • les stubs de bytecode générés dynamiquement pour Method::invoke et Constructor::newInstance, ainsi que l'accès non sécurisé aux champs pour Field::get et set.

Lorsque java.lang.reflect et java.lang.invoke sont mise à jour pour prendre en charge de nouvelles fonctionnalités du langage, comme celles envisagées dans le projet Valhalla, les trois chemins de code doivent être modifié, ce qui est coûteux. En outre, l'implémentation actuelle repose sur un traitement spécial par la VM du bytecode généré, qui est enveloppé dans des sous-classes de jdk.internal.reflect.MagicAccessorImpl :

  • La vérification est désactivée pour contourner JLS §6.6.2 afin de supporter la réflexion sur Object::clone ;
  • Un chargeur de classe non conforme est utilisé pour contourner certains problèmes de sécurité et de compatibilité ;
  • L'accessibilité est relâchée afin que ces classes puissent accéder aux champs et méthodes inaccessibles d'autres classes.

Description

La nouvelle implémentation effectue des invocations directes des poignées de méthodes pour des objets réfléchissants spécifiques. L’équipe Java Platform du Groupe Oracle utilise le mécanisme de réflexion natif de la VM uniquement au début du démarrage de la VM, avant l'initialisation du mécanisme de gestion des méthodes. Cela se produit peu après System::initPhase1 et avant System::initPhase2, après quoi nous passons à l'utilisation exclusive des method-handle. Cela profite au projet Loom en réduisant l'utilisation de cadres de pile natifs

Réimplémentation de java.lang.reflect sur les method handles en tant que mécanisme réflectif sous-jacent commun de la plate-forme en remplaçant les implémentations génératrices de bytecode de Method::invoke, Constructor::newInstance, Field::get et Field::set.
.
Pour des performances optimales, les instances de Method, Constructor et Field doivent être maintenues dans des champs statiques finaux afin qu'elles puissent être repliées en permanence par le JIT. Lorsque cela est fait, les microbenchmarks montrent que les performances de la nouvelle implémentation sont nettement plus rapides que celles de l'ancienne, de 43 à 57 %.

Lorsque les instances de méthode, de constructeur et de champ sont maintenues dans des champs non constants (par exemple, dans un champ non final ou un élément de tableau), les microbenchmarks montrent une certaine dégradation des performances. La performance des accès aux champs est significativement plus lente que l'ancienne implémentation, de 51-77 %, lorsque les instances Field ne peuvent pas être pliées de manière constante.

Cette dégradation peut toutefois ne pas avoir beaucoup d'effet sur les performances des applications du monde réel. L’équipe Java Platform du Groupe Oracle a effectué plusieurs tests de sérialisation et de désérialisation à l'aide de bibliothèques du monde réel et n’a constaté aucune dégradation des performances.

  • un benchmark de sérialiseur de champ Kryo ;
  • Un benchmark de type convertisseur XStream ;
  • Un benchmark personnalisé de sérialisation et désérialisation JSON utilisant Jackson.


L’équipe Java Platform du Groupe Oracle promet de continuer à explorer les possibilités d'améliorer les performances, par exemple en affinant les formes de bytecode pour l'accès aux champs afin de permettre aux MethodHandles et VarHandles concrets d'être optimisés de manière fiable par le JIT, que le récepteur soit constant ou non. La nouvelle implémentation réduira le coût de la mise à niveau du support de réflexion pour les nouvelles fonctionnalités du langage et, en outre, permettra à l’équipe Java Platform de simplifier la VM HotSpot en supprimant le traitement spécial des sous-classes MagicAccessorImpl.

Risques et hypothèses

Le code qui dépend d'aspects hautement spécifiques et non documentés de l'implémentation existante peut être affecté. Pour atténuer ce risque de compatibilité, les développeurs Java peuvent activer l'ancienne implémentation via -Djdk.reflect.useDirectMethodHandle=false.

Le code qui inspecte les classes de réflexion internes générées (c'est-à-dire les sous-classes de MagicAccessorImpl) ne fonctionnera plus et devra être mis à jour.
L'invocation de Method-handle peut consommer plus de ressources que l'ancienne implémentation de base de la réflexion. Une telle invocation implique l'appel de plusieurs méthodes Java pour s'assurer que la classe déclarante d'un membre est initialisée avant l'accès, et peut donc nécessiter plus d'espace de pile pour les cadres d'exécution nécessaires. Cela peut entraîner une StackOverflowError ou, si une StackOverflowError est lancée lors de l'initialisation d'une classe, une NoClassDefFoundError.

L’équipe Java Platform supprimera l'ancienne implémentation de base de la réflexion dans une prochaine version. La solution de contournement -Djdk.reflect.useDirectMethodHandle=false ne fonctionnera plus à ce moment-là.

SPI de résolution d'adresses Internet

Cette amélioration définit une interface de fournisseur de services (SPI) pour la résolution des noms et adresses d'hôtes, de sorte que java.net.InetAddress puisse utiliser des résolveurs autres que le résolveur intégré à la plateforme. L'API java.net.InetAddress résout les noms d'hôtes en adresses IP (Internet Protocol), et vice versa. L'API utilise actuellement le résolveur natif du système d'exploitation, qui est généralement configuré pour utiliser une combinaison d'un fichier d'hôtes local et du système de noms de domaine (DNS). Les motivations pour définir une interface de fournisseur de services pour la résolution de noms et d'adresses incluent :

  • Projet Loom : une opération de résolution avec l'API InetAddress se bloque actuellement dans un appel du système d'exploitation. C'est un problème pour les threads virtuels en mode utilisateur de Loom, car cela empêche les threads de la plate-forme sous-jacente de servir d'autres threads virtuels en attendant la fin d'une opération de résolution. Un autre résolveur pourrait mettre en œuvre le protocole client DNS directement, sans blocage ;
  • Protocoles réseau émergents : un résolveur SPI permettrait l'intégration transparente de nouveaux protocoles de résolution tels que le DNS sur QUIC, TLS ou HTTPS ;
  • Personnalisation : un résolveur SPI permettrait aux cadres et aux applications d'avoir un contrôle plus fin sur les résultats de résolution, et permettrait aux bibliothèques existantes d'être équipées d'un résolveur personnalisé ;
  • Test : les activités de prototypage et de test nécessitent souvent le contrôle des résultats de la résolution des noms d'hôtes et des adresses, par exemple lors de la simulation de composants qui utilisent l'API InetAddress.

Description

L'API InetAddress définit plusieurs méthodes pour les opérations de consultation :

  • InetAddress::getAllByName effectue une recherche vers l'avant, en associant un nom d'hôte à un ensemble d'adresses IP ;
  • InetAddress::getByName effectue également une recherche avant, en associant un nom d'hôte à la première adresse de son ensemble d'adresses ;
  • InetAddress::getCanonicalHostName effectue une recherche inverse, en faisant correspondre une adresse IP à un nom de domaine entièrement qualifié ;
    Par exemple :
    Code : Sélectionner tout
    1
    2
    3
    var addressBytes = new byte[] { (byte) 192, 0, 43, 7} ; 
    var resolvedHostName = InetAddress.getByAddress(addressBytes) 
                                      .getCanonicalHostName() ;
  • InetAddress::getHostName effectue également une recherche inverse, si nécessaire.
  • Par défaut, InetAddress utilise le résolveur natif du système d'exploitation pour effectuer les recherches. Le résultat de cette recherche, qu'il soit positif ou négatif, peut être mis en cache afin d'éviter d'autres recherches sur le même hôte.

Interface du fournisseur de services

L'API InetAddress utilise un chargeur de services pour localiser un fournisseur de résolveur. Si aucun fournisseur n'est trouvé, l'implémentation intégrée sera utilisée comme auparavant. Les nouvelles classes du paquet java.net.spi sont :

[LIST][*]InetAddressResolverProvider : une classe abstraite définissant le service à localiser par java.util.ServiceLoader. Un InetAddressResolverProvider est, essentiellement, une usine pour les résolveurs. Le résolveur instancié sera défini comme le résolveur du système, et InetAddress déléguera toutes les demandes de recherche à ce résolveur ;[*]InetAddressResolver : une interface qui définit les méthodes pour les opérations fondamentales de recherche en avant et en arrière. Une instance de cette interface est obtenue à partir d'une instance de InetAddressResolverProvider ;[*]InetAddressResolver.LookupPolicy : classe dont les instances...
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.

Une erreur dans cette actualité ? Signalez-nous-la !