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 PKCS#12 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 PKCS#12 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 PKCS#12 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.