BT

Diffuser les Connaissances et l'Innovation dans le Développement Logiciel d'Entreprise

Contribuez

Sujets

Sélectionner votre région

Accueil InfoQ Articles Java 18 - Partie 2

Java 18 - Partie 2

Points Clés

  • Java 18 a été publié le 22 mars 2022
  • Comme dans toutes les versions depuis Java 12, des fonctionnalités sont dépréciées forRemoval ou retirées
  • Plusieurs améliorations sont apportées dans les ramasse-miettes
  • Des améliorations sont aussi apportées sur les performances
  • Ainsi que de nombreuses améliorations relatives à la sécurité
  • Plusieurs fournisseurs proposent une distribution du JDK 18 pour différentes plateformes

Après avoir détaillé les différentes JEPs de Java 18 dans la première partie de cet article, cette seconde partie est consacrée aux autres améliorations notamment en termes de performance et de sécurité ainsi que le support de Java 18 par l’outillage.

Car comme toute version de Java, cette version 18 inclut quelques JEPs mais aussi et surtout des améliorations sur la fiabilité (corrections de nombreux bugs), la performance et la sécurité.

 

Les fonctionnalités dépréciées ou retirées

Comme dans toutes les versions depuis Java 12, des fonctionnalités sont dépréciées forRemoval ou retirées. Ces dernières peuvent induire des incompatibilités avec la version précédente de Java.

En plus des fonctionnalités dépréciées par la JEP 421, plusieurs autres fonctionnalités sont dépréciées ou retirées.

Les méthodes finalize() des classes java.awt.color.ICC_Profile, java.awt.image.ColorModel et java.awt.image.ColorModel.IndexColorModel du module java.desktop sont supprimées. Elles étaient dépréciées depuis Java 9 et dépréciées forRemoval depuis Java 16 (JDK-8273102).

Les implémentations historiques de java.net.SocketImpl et java.net.DatagramSocketImpl sont supprimées. Elles n’étaient plus utilisées par défaut, respectivement depuis Java 13 et Java 15. Les propriétés système de la JVM jdk.net.usePlainSocketImpl et jdk.net.usePlainDatagramSocketImpl sont aussi supprimées puisqu’elles sont de fait inutiles (JDK-8253119).

Pour poursuivre la suppression des API relatives au Security Manager, les deux surcharges de la méthode doAs() de la classe javax.security.auth.Subject sont dépréciées forRemoval (JDK-8267108).

Les méthodes objectFieldOffset(), staticFieldOffset() et staticFieldBase() de la classe sun.mic.Unsafe sont dépréciées (JDK-8277863).

La méthode stop() de la classe Thread, dépréciée depuis Java 1.2 est dépréciée forRemoval=true (JDK-8277861).

 

Les améliorations dans les ramasse-miettes

La liste complète des nombreux changements dans les ramasse-miettes de Java 18 est consultable ici.

Parmi les plus marquants, il y a notamment :

  • La fonctionnalité String deduplication (JEP 192) utilisable avec G1 est aussi maintenant utilisable avec les ramasse-miettes SerialGC (JDK-8272609), Parallel GC (JDK-8267185) et ZGC (JDK-8267186). L’utilisation de cette fonctionnalité se fait avec l’option -XX:+UseStringDeduplication de la JVM Hotspot
  • L’option -XX:GCCardSizeInBytes permet de configurer la taille des cards de la table des cards utilisée par les ramasse-miettes Serial, Parallel et G1. Historiquement la valeur est 512 octets. La valeur par défaut reste 512 mais les valeurs possibles sont maintenant 128, 256, 512 et 1024 (uniquement sur des architectures 64bits). La modification de cette valeur peut avoir un impact positif ou négatif sur la durée des pauses. Une description détaillée est fournie dans ce post de blog.
  • ZGC est porté sur PPC64 (JDK-8274851)
  • Le Serial GC ajoute la prise en charge des objets du heap archivés de CDS. Cela peut améliorer le temps de démarrage de la JVM. L'utilisation est la même que dans G1. (JDK-8273508)

Le ramasse-miettes G1 contient aussi plusieurs améliorations :

  • La réduction de sa consommation en mémoire native (JDK-8017163)
  • La taille des régions, historiquement limitée à 32Mo, est maintenant limitée à 512Mo.  (JDK-8275056). La taille des régions du heap déterminée par les ergonomics est toujours limitée à 32 Mo maximum. Il est possible d’utiliser l’option -XX:G1HeapRegionSize pour augmenter la taille des régions jusqu’à 512Mo. Ceci peut être utilisé pour atténuer les problèmes de fragmentation interne et externe avec des objets de grande taille dans des heaps de grande taille. Sur de très grands heap, augmenter la taille de régions peut améliorer les performances
  • Le nombre d’échecs d'évacuation qui augmente de manière significative le temps de pause est réduit
  • G1 arrête ces traitements immédiatement lors d’un arrêt de la JVM. Avant, dans certains cas, G1 attendait l'achèvement d'un marquage concurrent actif lorsque l'application Java est sur le point de quitter pour effectivement quitter, ce qui pouvait entraîner de longs délais selon la complexité de cette tâche. (JDK-8273605)
  • Une régression des performances introduite en Java 14 sur des machines avec de nombreux cœurs dans le cas où un grand tableau d’objets est directement créé dans la old generation à cause de sa taille est corrigée (JDK-8278824)
  • Les options -XX:G1RSetRegionEntries and -XX:G1RSetSparseRegionEntries sont maintenant obsolètes (JDK-8017163). Leur utilisation affiche un avertissement

 

Les améliorations de performances

En plus des améliorations de performance introduites dans les améliorations des ramasse-miettes présentées ci-dessus, plusieurs autres améliorations de performance sont proposées dans Java 18.

Plusieurs améliorations de performances ont été apportées aux composants de chiffrement, TLS et JAAS/Kerberos : consultez JDK-8270317, JDK-8276660, JDK-8273299, JDK-8268427, JDK-8267125, et JDK-8273026 pour plus de détails.

 

Références d’instances englobantes omises dans les classes internes qui ne les utilisent pas

Avant Java 18, le compilateur javac ajoute systématiquement un champ private synthétique du type de la classe englobante nommé this$0.

Exemple :

public class MaClasse {

  class MaClasseInterne{
  }
}
C:\java>javac -version
javac 17

C:\java>javac MaClasse.java

C:\java>javap -c -s MaClasse$MaClasseInterne
Compiled from "MaClasse.java"
class MaClasse$MaClasseInterne {
  final MaClasse this$0;
    descriptor: LMaClasse;

  MaClasse$MaClasseInterne(MaClasse);
    descriptor: (LMaClasse;)V
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #1                  // Field this$0:LMaClasse;
       5: aload_0
       6: invokespecial #7                  // Method java/lang/Object."":()V
       9: return
}

A partir de Java 18, le compilateur javac n’ajoute plus le champ this$0 si ce dernier n’est pas utilisé (JDK-8271623).

C:\java>javac -version
javac 18

C:\java>javac MaClasse.java

C:\java>javap -c -s MaClasse$MaClasseInterne
Compiled from "MaClasse.java"
class MaClasse$MaClasseInterne {
  MaClasse$MaClasseInterne(MaClasse);
    descriptor: (LMaClasse;)V
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."":()V
       4: return
}

C:\java>

Note : pour des raisons de compatibilité, le constructeur de la classe interne attend toujours un paramètre du type de la classe englobante.

Ce changement peut permettre aux ramasse-miettes de récupérer plus rapidement les instances englobantes, si auparavant elles n'étaient accessibles que par une référence dans une classe interne. Cela pourra éviter de maintenir une instance de la classe englobante qui n’est plus utile mais dont une référence était conservée auparavant dans l’instance de la classe interne.

 

La sécurité

Java 18 apporte des améliorations au niveau de la sécurité pour renforcer la sécurité par défaut de la plate-forme Java, la prise en charge de nouveaux algorithmes de chiffrement et de nouvelles méthodes dans l’API JAAS qui sont des alternatives qui ne dépendent pas du Security Manager déprécié.

Les certificats racines expirés ont été retirés du keystore cacerts (Globalsign et DST Root CA X3). (JDK-8225083) et (JDK-8225082)

Les algorithmes de chiffrement faibles (utilisant DES, 3DES, RC4) ont été supprimés de la liste par défaut des algorithmes de chiffrement Kerberos. Ces algorithmes avaient été préalablement désactivés. (JDK-8273670)

 

Les JARs signés avec SHA-1 sont désactivés

Les JARs signés avec des algorithmes SHA-1 sont maintenant désactivés par défaut et traités comme s'ils étaient non signés (JDK-8269039). SHA-1 est un algorithme de calcul d’empreinte qui est devenu de plus en plus faible et qui ne devrait plus être utilisé pour les signatures numériques.

Cela s'applique aux algorithmes utilisés pour calculer une empreinte numérique, signer et éventuellement horodater le JAR. Cela s'applique également aux algorithmes de signature et de calcul d’empreinte des certificats de la chaîne de certificats du signataire du code et de l'autorité d'horodatage, ainsi qu'à toute réponse CRL ou OCSP utilisée pour vérifier si ces certificats ont été révoqués.

Pour limiter les risques d’incompatibilité dans les applications existantes, il existe une exception à cette politique : les JAR signés avec des algorithmes SHA-1 et horodaté avant le 01 janvier 2019 ne sera pas restreint.

Attention : cette exception sera supprimée dans une future version de Java. Il est donc fortement recommandé de resigner tout JAR signé avec SHA-1 avec un algorithme plus fort.

L'outil jarsigner a également été amélioré pour détecter plus précisément et avertir si un JAR est affecté par ces restrictions. L’utilisation de cet outil avec les options -verify et -verbose permet de voir si des JARs sont concernés. Si c’est le cas, l’outil affiche un avertissement. Exemple :

- Signed by "CN=oxiane"
    Digest algorithm: SHA-1 (disabled)
    Signature algorithm: SHA256withRSA, 2048-bit key

WARNING: The jar will be treated as unsigned, because it is signed with a weak algorithm that is now disabled by the security property:

  jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, DSA keySize < 1024, SHA1 denyAfter 2019-01-01

Il est possible, en toute connaissance des conséquences, de supprimer ces restrictions en modifiant le fichier de configuration java.security (ou en le remplaçant par la propriété système de la JVM java.security.properties) et en supprimant "SHA1 usage SignedJAR & denyAfter 2019-01-01" de la propriété de sécurité jdk.certpath.disabledAlgorithms et "SHA1 denyAfter 2019-01-01" de la propriété de sécurité jdk.jar.disabledAlgorithms.

 

Le keystore cacerts utilise le format PKCS12 sans mot de passe par défaut

Le keystore cacerts, qui contient les certificats racines des autorités de certification fournis avec le JDK, utilise maintenant le format standard PKCS12 en remplacement du format non standard.

En Java 9, l’outil keytools utilise par défaut PKCS#12 en remplacement du format JKS historique.

Historiquement, le keystore cacerts utilise le format JKS et est protégé par un mot de passe par défaut : changeit

C:\java
λ java -version
openjdk version "17" 2021-09-14
OpenJDK Runtime Environment (build 17+35-2724)
OpenJDK 64-Bit Server VM (build 17+35-2724, mixed mode, sharing)

C:\java
λ keytool -list -cacerts | head -n 4
Enter keystore password:  changeit
Keystore type: JKS
Keystore provider: SUN

Your keystore contains 91 entries 

A partir de Java 18, le keystore cacerts utilise le format PKCS#12 sans mot de passe (JDK-8275252). Comme le format PKCS#12 supporte un keystore sans mot de passe : il n’y a plus de mot de passe à spécifier par défaut pour accéder au cacerts.

C:\java
λ java -version
openjdk version "18" 2022-03-22
OpenJDK Runtime Environment (build 18+36-2087)
OpenJDK 64-Bit Server VM (build 18+36-2087, mixed mode, sharing)

C:\java
λ keytool -list -cacerts | head -n 4
Keystore type: PKCS12
Keystore provider: SUN

Your keystore contains 89 entries

Aucun mot de passe ou un mot de passe connu de tous, ne dégrade par le niveau de sécurité du keystore cacerts.

Attention : sans mot de passe les certificats contenus dans un keystore ne sont pas chiffrés. Il est toujours possible de définir un mot de passe surtout si des certificats doivent être ajoutés au keystore cacerts.

 

Permettre au mot de passe d'être null dans un keystore PKCS12

Les keystores sans mot de passe pour le déverrouiller sont utiles lorsqu’ils ne sont utilisés que pour stocker des certificats X.509 publics, comme c’est le cas avec le cacerts et qu’ils sont dans un répertoire sécurisé.

Avec un keystore PKCS12 sans mot de passe, les certificats ne sont pas chiffrés et il n'y a pas de MacData appliqué car un contrôle d'intégrité n'est pas nécessaire.

Avant ce changement, la création d’un keystore PKCS12 sans mot de passe était compliqué mais maintenant c’est très facile (JDK-8231107). Il suffit de passer null comme valeur au paramètre password de la méthode store(outStream, password) de la classe KeyStore. Pour accéder à un keystore sans mot de passe, il faut passer la valeur null au paramètre password de la méthode load() de la classe KeyStore.

Exemple pour créer un keystore sans mot de passe

    KeyStore ks = KeyStore.getInstance("pkcs12");
    char[] motDePasse = null;
    ks.load(null, motDePasse);
    try (FileOutputStream fos = new FileOutputStream("monkeystore.jks")) {
      ks.store(fos, motDePasse);
    }

Le keystore créé est utilisable sans fournir de mot de passe :

C:\java>keytool -list -keystore monkeystore.jks
Keystore type: PKCS12
Keystore provider: SUN

Your keystore contains 0 entries

 

Deux nouvelles méthodes dans l’API JAAS comme alternative sans Security Manager

Deux nouvelles méthodes current() et callAs() dans la classe javax.security.auth.Subject ont été ajoutées comme alternatives respectivement aux méthodes getSubject() et doAs() qui sont dépréciées forRemoval (JDK-8267108).

Les méthodes getSubject() et doAs() dépendent de l’API Security Manager même si elles ne requièrent pas qu’un Security Manager soit utilisé.

 

Support dans PKCS#11 des modes AES Key Wrap et AES Key Wrap With Padding (KWP)

Le fournisseur SunPKCS11 a été enrichi pour prendre en charge les algorithmes de chiffrement cryptographique utilisant les modes AES Key Wrap (KW) et AES Key Wrap With Padding (KWP) lorsque la bibliothèque PKCS11 sous-jacente prend en charge les mécanismes PKCS#11 correspondants (JDK-8264849).

La correspondance entre les algorithmes JCE et les mécanismes de PKCS11 sont :

Algorithme de chiffrement JCE

Mécanisme de PKCS11

AES/KW/NoPadding

CKM_AES_KEY_WRAP

AES/KW/PKCS5Padding

CKM_AES_KEY_WRAP_PAD

AES/KWP/NoPadding

CKM_AES_KEY_WRAP_KWP

Ces modes standard sont conçus pour protéger les clés de chiffrement et sont définis dans le NIST SP 800-38F et sont ajoutés dans la version 3.0 de PKCS#11.

Pour les utiliser, il suffit de passer le mode en paramètre de la méthode getInstance() de la classe javax.crypto.Cipher.

Cipher c = Cipher.getInstance("AES/KW/PKCS5Padding");

 

La valeur par défaut de la propriété système de la JVM java.security.manager est disallow

Comme annoncé dans la JEP 411, la valeurs par défaut de la propriété java.security.manager passe de allow à disallow  (JDK-8270380). Cela améliore les performances des applications qui n’utilisent pas de Security Manager.

Attention : cette modification a un impact sur les applications qui utilisent leur propre Security Manager défini en utilisant la méthode setSecurityManager() de la classe System. Il faut mettre la valeur allow à la propriété système de la JVM java.security.manager sinon la méthode setSecurityManager() lève une exception de type UnsupportedOperationException.

java -Djava.security.manager=allow MonApp

 

Les autres évolutions

Il y a aussi de nombreuses autres évolutions : consultez les release notes pour une liste intégrale.

 

Les distributions de Java 18

Plusieurs fournisseurs proposent une distribution d’un JDK 18 pour différentes plateformes, notamment :

Fournisseur

Distribution

License

Plateformes

Adoptium

Eclipse Temurin

GPLv2+CE

alpine-x64
linux-arm
linux-aarch64
linux-ppc64le
linux-s390x
linux-x64
macos-x64
windows-x86
windows-x64

Amazon

Corretto 18

GPLv2+CE

alpine-x64
linux-arm64
linux-x64
macos-arm64
macos-x64
windows-x64

Azul Systems

Zulu Builds of OpenJDK 18

GPLv2+CE

alpine-arm64
alpine-x64
linux-arm64
linux-x86
linux-x64
macos-arm64
macos-x64
windows-arm64
windows-x86
windows-x64

BellSoft

Liberica

GPLv2+CE

alpine-arm64
alpine-x64
linux-arm32
linux-arm64
linux-ppc64le
linux-x86
linux-x64
macos-arm64
macos-x64
windows-arm64
windows-x86
windows-x64

Oracle

Oracle JDK 18

Oracle No-Fee

linux-arm64
linux-x64
macos-arm64
macos-x64
windows-x64

Oracle

Oracle OpenJDK 18

GPLv2+CE

linux-arm64
linux-x64
macos-arm64
macos-x64
windows-x64

SAP

SapMachine 18

GPLv2+CE

linux-ppc64le
linux-x64
macos-arm64
macos-x64
windows-x64

 

Le support par les outils

Eclipse 2022-03 (4.23) requiert un plugin, à installer en plus, disponible dans la marketplace pour le support de Java 18.

Jetbrains IntelliJ IDEA version 2022.1 propose un support de Java 18.

 

Conclusion

Les améliorations relatives à la performance et à la sécurité devraient être des arguments majeurs pour une montée de version de Java.

Attention cependant, Java 18 est une version non-LTS, son support ne durera que 6 mois, jusqu’à la publication de Java 19 en septembre prochain.

Alors téléchargez une distribution d’un JDK 18 et testez ces fonctionnalités.

 

Au sujet de l’Auteur

Evaluer cet article

Pertinence
Style

Contenu Éducatif

BT