
Six mois se sont écoulés, ce qui signifie qu'il est temps d'installer de nouveaux Java ! Ce fut un long voyage et peu atteignirent la fin. Les lignes brutes sont tombées des JEP intéressants, mais nous parlerons du reste sous la coupe.
Comment ça se passe
La sortie de la nouvelle version de Java se déroule selon le nouveau cycle de sortie «accéléré» d'une durée d'environ six mois. Les dates exactes sont définies sur la page du projet . Il y a eu plusieurs phases principales pour JDK 12:
- 13/12/2018 - La première phase du ralentissement (en ce moment, un fork est réalisé à partir de la branche principale du référentiel);
- 2019/01/17 - La deuxième phase du ralentissement (achever tout ce qui est possible);
- 07/02/2019 - Release candidate (seuls les bugs les plus importants sont corrigés);
- 2019/03/19 - Sortie, disponibilité générale. <- vous êtes ici
Qu'avons-nous de ce calendrier? Oui, en fait, rien - nous venons d'arriver à la ligne d'arrivée, et nous regardons les amoureux de l'héritage du haut du tout nouveau JDK 12.
Bugs! Panique! Tout en bas!

Lorsqu'une nouvelle version non LTS sort, généralement tout le monde s'en fout des nouvelles fonctionnalités. C'est plus intéressant si tout s'écroule en enfer.
Bien sûr, il y a beaucoup de bugs, mais pas dans JDK 12 :) A en juger par le jir, tout est normal:

Je citerai la demande pour que vous compreniez exactement ce qu'est la "norme":
project = JDK AND issuetype = Bug AND status in (Open, "In Progress", New) AND priority in (P1) AND (fixVersion in (12) OR fixVersion is EMPTY AND affectedVersion in (12) AND affectedVersion not in regexVersion("11.*", "10.*", "9.*", "8.*", "7.*", "6.*")) AND (labels is EMPTY OR labels not in (jdk12-defer-request, noreg-demo, noreg-doc, noreg-self)) AND (component not in (docs, globalization, infrastructure) OR component = infrastructure AND subcomponent = build) AND reporter != "Shadow Bug" ORDER BY priority, component, subcomponent, assignee
Bien sûr, en général, les bugs ont leur place, ils n'iront nulle part dans un projet aussi énorme. Il est seulement affirmé que pour l'instant, les bogues P1 n'ont pas été remarqués.
Une communication plus formelle avec les bogues est déclarée dans un document spécial, JEP 3: JDK Release Process , qui appartient à notre intendant immortel sur les vagues turbulentes de l'océan Java - Mark Reinhold.
Et en particulier, il vaut la peine de déterrer un paragraphe racontant qui est à blâmer et que faire comment transférer des billets si vous n'avez pas le temps pour la 12e version. Il est nécessaire de mettre dans le bugtracker l'étiquette jdk$N-defer-request
dans laquelle N indique la version à partir de laquelle vous souhaitez transférer, et de laisser un commentaire, dont la première ligne est Deferral Request . En outre, l'examen de toutes ces demandes est effectué par les responsables des domaines et projets respectifs.
Les problèmes de passage de TCK ne peuvent pas être ignorés de cette façon - il est garanti que Java reste Java, et non quelque chose comme une grenouille. L' jdk$N-defer-request label
ne disparaît jamais. C'est intéressant ce qu'ils font avec les gens qui violent la règle de ne pas supprimer les étiquettes - je suggère de nourrir les cobayes.
Cependant, de cette façon, vous pouvez voir combien de bogues ont été portés sur JDK 13. Essayons cette requête:
project = JDK AND issuetype = Bug AND status in (Open, "In Progress", New) AND (labels in (jdk12-defer-request) AND labels not in (noreg-demo, noreg-doc, noreg-self)) AND (component not in (docs, globalization, infrastructure) OR component = infrastructure AND subcomponent = build) AND reporter != "Shadow Bug" ORDER BY priority, component, subcomponent, assignee
Seulement 1 pièce, JDK-8216039 : "TLS avec BC et RSASSA-PSS casse ECDHServerKeyExchange". Ce n'est pas épais. Si cet argument n'aide toujours pas, alors, en tant qu'avocat, je recommande d'essayer un sédatif.
Et quel est le résultat net?

Il est clair que la plupart des fonctionnalités n'affectent pas les utilisateurs (programmeurs Java), mais les développeurs d'OpenJDK lui-même. Par conséquent, juste au cas où, je divise les fonctionnalités en externes et internes . Vous pouvez sauter les internes, mais je suis offensé, j'ai écrit tellement de texte.
189: Shenandoah: un ramasse-miettes à faible pause (expérimental)
Fonction externe . En bref, les gens n'aiment pas cela lorsque Java ralentit, surtout si le SLA nécessite une réactivité de l'ordre de 10 à 500 millisecondes. Nous avons maintenant un GC low-punch gratuit qui essaie de travailler plus près du bord gauche de cette plage. Le compromis est que nous échangeons le CPU et la RAM pour réduire la latence. Les phases de marquage et de compactage de la hanche fonctionnent en parallèle avec les threads d'application en direct. Les petites pauses restantes sont dues au fait que vous devez toujours rechercher et mettre à jour les racines du graphique des objets.
Si rien de ce qui précède n'a de sens pour vous - cela n'a pas d'importance, Shenandoah fonctionne simplement , indépendamment de la compréhension ou de la non-compréhension des processus sous-jacents.
Alexei Shipilev, Christina Flood et Roman Kennke y travaillent - vous devez vous efforcer de ne pas connaître ces gens. Si vous comprenez généralement le fonctionnement de GC mais n’imaginez pas ce qu’un développeur peut faire là-bas, je vous recommande de regarder la merveilleuse traduction du merveilleux article de Leshina «Homemade Garbage Collector for OpenJDK» ou la série JVM Anatomy Quarks . C'est très intéressant .
Extrêmement important. Oracle a décidé de ne pas expédier Sheandoah avec aucune de ses versions de version - ni celle sur jdk.java.net ni celle sur oracle.com. Étant donné que Shenandoah est l'une des caractéristiques les plus importantes du JDK 12, il vaut la peine d'installer un autre assemblage officiel, par exemple, d'Azul .
230: Microbenchmark Suite
Caractéristique intérieure . Si vous avez déjà essayé d'écrire des microbenchmarks, vous savez que cela se fait sur JMH. JMH est un framework pour créer, assembler, lancer et analyser des microbenchmarks pour Java et d'autres langages JVM, vous savez vous- même qui l'a écrit (toutes les correspondances sont aléatoires). Malheureusement, tout ce qui se fait dans le monde des applications "normales" ne peut pas être appliqué à l'intérieur du JDK. Par exemple, il est peu probable que nous y voyions du code Spring Framework normal.
Heureusement, à partir de la version 12, vous pouvez utiliser au moins JMH, et il existe déjà un ensemble de tests qui y sont écrits. Vous pouvez le voir dans jdk/jdk/test/micro/org/openjdk/bench
(vous pouvez regarder directement dans le navigateur, ce chemin est un lien).
Par exemple, voici à quoi ressemble le test GC .
Permettez-moi de vous rappeler que nous n'avons pas StackOverflow ici, et il est interdit d'utiliser le code du copier-coller, ici et ci-après, sans lire et observer toutes les licences du fichier correspondant et du projet OpenJDK en général, sinon vous obtiendrez facilement les dernières chaussettes poursuivies.
@BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Thread) public class Alloc { public static final int LENGTH = 400; public static final int ARR_LEN = 100; public int largeLen = 100; public int smalllen = 6; @Benchmark public void testLargeConstArray(Blackhole bh) throws Exception { int localArrlen = ARR_LEN; for (int i = 0; i < LENGTH; i++) { Object[] tmp = new Object[localArrlen]; bh.consume(tmp); } }
325: Changer d'expressions (préversion)
Fonction externe . Cela changera fondamentalement votre approche de l'écriture de commutateurs sans fin avec une longueur de plus de deux écrans. Regardez:
Virgin Java Switch vs ...
int dayNum = -1; switch (day) { case MONDAY: case FRIDAY: case SUNDAY: dayNum = 6; break; case TUESDAY: dayNum = 7; break; case THURSDAY: case SATURDAY: dayNum = 8; break; case WEDNESDAY: dayNum = 9; break; }
Pourquoi c'est mauvais : il y a beaucoup de lettres, vous pouvez sauter la pause (surtout si vous êtes toxicomane ou malade du TDAH).
... vs Chad Java Swtich Expression!
int dayNum = switch (day) { case MONDAY -> 0; case TUESDAY -> 1; default -> { int k = day.toString().length(); int result = f(k); break result; } };
Pourquoi bon : quelques lettres, sûr, pratique, nouvelle fonctionnalité cool.
Bonus : si vous êtes sadique, cela vous donnera la plus grande satisfaction, car des milliers de développeurs IDE sont maintenant tourmentés par le support de cette fonctionnalité. Oui lany , oui? Vous pouvez le rattraper après le rapport du 6 avril et lui demander gentiment de donner tous les détails sales.
Ceci est une fonctionnalité de prévisualisation, cela ne fonctionnera tout simplement pas! Lors de la compilation, dans javac
vous devez passer les options de ligne de commande --enable-preview --release 12
, et pour exécuter via java
- uniquement l'indicateur --enable-preview
.
334: API des constantes JVM
Caractéristique intérieure . Les développeurs veulent manipuler les fichiers de classe. Vous devez le faire facilement, et c'est l'énoncé du problème. C'est du moins ce que Brian Goetz, propriétaire de ce JEP, a déclaré :-) Tout cela fait partie d'un champ de bataille plus large, mais pour l'instant nous n'irons pas en profondeur.
Chaque classe Java a un soi-disant "pool constant", où il y a un vidage de certaines valeurs (comme les chaînes et les entiers), ou d'entités d'exécution comme les classes et les méthodes. Vous pouvez creuser dans ce vidage en utilisant l'instruction ldc - "load costant", donc toutes ces ordures sont appelées constantes chargeables. Il existe encore un cas particulier pour la dynamique invoquée, mais tant pis.
Si nous travaillons avec des fichiers de classe, nous voulons simuler facilement les instruments de bytecode, et donc les constantes chargeables. Le premier souhait est de simplement créer les types Java correspondants, mais comment les présenter avec une classe "vivante", la structure CONSTANT_Class_info
? Class
objets de Class
dépendent de l'exactitude et de la cohérence du chargement des classes, et avec le chargement des classes en Java, une bacchanale infernale est créée. Pour commencer, toutes les classes ne peuvent pas être chargées dans la VM, mais vous devez toujours les décrire!
Je voudrais en quelque sorte gérer des choses comme les classes, les méthodes et les bêtes moins connues comme les poignées de méthode et les constantes dynamiques, en tenant compte de toutes ces subtilités.
Ceci est résolu en introduisant de nouveaux types de liens symboliques basés sur des valeurs (au sens de JVMS 5.1 ), chacun décrivant un type spécifique de constante. Décrit purement nominalement, indépendamment des classes de chargement ou des problèmes d'accès. Ils vivent dans des packages comme java.lang.invoke.constant
et ne le demandent pas, mais vous pouvez jeter un œil au patch ici .
340: un port AArch64, pas deux
Fonction externe . Déjà dans JDK 9, il y avait une situation étrange quand Oracle et Red Hat mettaient simultanément leurs ports ARM en alerte. Et maintenant, nous voyons la fin de l'histoire: la partie 64 bits du port d'Oraklov a été retirée de l'amont.
Vous auriez pu vous plonger dans l'histoire pendant longtemps, mais il y a une meilleure façon. BellSoft a participé au développement de ce JEP, et son bureau est situé à Saint-Pétersbourg, à côté de l'ancien bureau d'Oracle.
Par conséquent, je me suis immédiatement tourné immédiatement vers Alexey Voitilov, CTO de BellSoft:
"BellSoft lance le Liberica JDK, qui, en plus de x86 Linux / Windows / Mac et Solaris / SPARC, prend également en charge ARM. En commençant par JDK 9 pour ARM, nous nous sommes concentrés sur l'amélioration des performances du port AARCH64 pour les applications serveur et avons continué à prendre en charge le port ARM 32 bits pour Ainsi, au moment de la sortie de JDK 11, il y avait une situation où personne ne supportait la partie port 64 bits d'Oracle (y compris Oracle), et la communauté OpenJDK a décidé de la supprimer afin de se concentrer sur le port AARCH64. voir, par exemple, JEP 315 , que nous intégré dans JDK 11) et, à partir de JDK 12, il prend en charge toutes les fonctionnalités présentes dans le port d'Oracle (le dernier, Minimal VM, j'ai intégré en septembre). Par conséquent, j'ai été heureux d'aider Bob Vandette à supprimer ce rudiment dans JDK 12. En conséquence, OpenJDK la communauté a reçu un port sur AARCH64 et un port ARM32, ce qui les rend certainement plus faciles à prendre en charge. "
341: Archives CDS par défaut
Caractéristique intérieure . Le problème est qu'au démarrage d'une application Java, des milliers de classes sont chargées, ce qui donne l'impression que Java ralentit considérablement au démarrage. Mais qui est là pour mentir, ce n'est pas seulement une «sensation» - c'est le cas. Pour résoudre le problème des temps anciens, divers rituels sont pratiqués.
Le partage de données de classe est une fonctionnalité qui nous est venue depuis des temps immémoriaux , comme une fonctionnalité commerciale de JDK 8 Update 40. Il vous permet de regrouper toutes ces ordures de démarrage dans une archive de votre propre format (vous n'avez pas besoin de savoir lequel), après quoi la vitesse de lancement les applications augmentent. Et après un certain temps, JEP 310 est apparu: Application Class-Data Sharing, qui nous a permis de travailler de la même manière non seulement avec les classes système, mais aussi avec les classes d'application.
Pour les classes JDK, cela ressemble à ceci. Tout d'abord, nous vidons les classes avec la commande java -Xshare:dump
, puis java -Xshare:dump
l'application en lui disant d'utiliser ce cache: java -Xshare:on -jar app.jar
. Tout, la startup s'est un peu améliorée. Connaissiez-vous cette fonctionnalité? Beaucoup qui ne savent toujours pas!
Cela semble étrange ici: pourquoi à chaque fois écrire rituellement -Xshare:dump
si le résultat par défaut de cette commande est un peu prévisible même au stade de la création de la distribution JDK? Selon la documentation , si la distribution Java 8 a été installée à l'aide du programme d'installation, alors au moment de l'installation, elle devrait exécuter les commandes nécessaires pour vous. Comme, l'installateur est en train d'explorer tranquillement dans le coin. Mais pourquoi? Et que faire de la distribution, qui n'est pas distribuée en tant qu'installateur, mais en tant que fichier zip?
C'est simple: à partir de JDK 12, l'archive CDS sera générée par les créateurs du kit de distribution, immédiatement après la liaison. Même pour les versions nocturnes (à condition qu'elles soient 64 bits et natives, pas pour la compilation croisée).
Les utilisateurs n'ont même pas besoin de connaître la présence de cette fonctionnalité, car, à partir de JDK 11, -Xshare:auto
activé par défaut, et une telle archive sera automatiquement -Xshare:auto
. Ainsi, le simple fait de passer à JDK 12 accélère le lancement de l'application!
344: Collections mixtes avortables pour G1
Caractéristique intérieure . Pour être honnête Je ne comprends rien au travail de G1 Une explication des caractéristiques de GC est une tâche ingrate. Cela nécessite une compréhension des détails de son travail à la fois de l'explicateur et de la compréhension. Pour la plupart des gens, GC est une sorte d'enfer d'une tabatière que vous pouvez tricher en cas de quelque chose. Par conséquent, le problème doit être expliqué d'une manière ou d'une autre plus simple.
Problème : G1 pourrait mieux fonctionner.
Eh bien, le problème est que le GC est un compromis de nombreux paramètres, dont l'un est la durée de la pause. Parfois, la pause est trop longue, puis c'est agréable de pouvoir l'annuler.
Quand cela se produit-il? G1 analyse réellement le comportement de l'application et sélectionne le front du travail (exprimé comme un ensemble de collections ) en fonction de ses conclusions. Lorsque l'étendue des travaux est approuvée, G1 s'engage à collecter tous les objets vivants de l'ensemble de collecte, obstinément et sans arrêt, en une seule séance. Parfois, cela prend trop de temps. En substance, cela signifie que G1 a incorrectement calculé la quantité de travail. Vous pouvez le tromper en modifiant soudainement le comportement de votre application afin que l'heuristique fonctionne au-dessus des données incorrectes lorsqu'un trop grand nombre d'anciennes régions pénètrent dans l'ensemble de collecte.
Afin de sortir de la situation, G1 a été finalisé par le mécanisme suivant: si l'heuristique sélectionne régulièrement la mauvaise quantité de travail, G1 passe à la collecte incrémentielle des ordures, étape par étape, et chaque étape suivante (si elle ne rentre pas dans le temps d'exécution cible) peut être annulée. Il n'est pas logique de collecter quelque chose de manière incrémentielle (régions jeunes), par conséquent, tous ces travaux sont mis en évidence dans le bloc «obligatoire», qui est toujours effectué en continu.
Que faire avec l'utilisateur final? Rien, vous devez passer à JDK 12, tout ira mieux de lui-même.
346: renvoyer rapidement la mémoire validée inutilisée de G1
Caractéristique intérieure . Le problème est que si nous avons une grosse hanche que personne n'utilise activement, il semble juste de ramener toute cette mémoire inactive au système d'exploitation. Cependant, avant JDK 12, cela ne s'était pas produit.
Afin d'atteindre son objectif en termes de durée de pause autorisée, G1 effectue un ensemble de cycles incrémentiels, parallèles et à plusieurs étages. Dans JDK 11, il ne donne de mémoire engagée au système d'exploitation qu'avec un GC complet, ou pendant la phase de marquage parallèle. Si vous connectez la journalisation (-Xloggc: /home/gc.log -XX: + PrintGCDetails -XX: + PrintGCDateStamps), alors cette phase s'affiche quelque chose comme ceci:
8801.974: [G1Ergonomics (Concurrent Cycles) request concurrent cycle initiation, reason: occupancy higher than threshold, occupancy: 12582912000 bytes, allocation request: 0 bytes, threshold: 12562779330 bytes (45.00 %), source: end of GC] 8804.670: [G1Ergonomics (Concurrent Cycles) initiate concurrent cycle, reason: concurrent cycle initiation requested] 8805.612: [GC concurrent-mark-start] 8820.483: [GC concurrent-mark-end, 14.8711620 secs]
Ce qui est drôle, c'est que G1, comme il peut, a du mal avec des arrêts complets, et le cycle simultané ne commence qu'avec des allocations fréquentes et un tas obstrué. Notre situation, lorsque personne ne touche la hanche, est tout le contraire. Les situations où G1 gratte pour donner de la mémoire au système d'exploitation se produiront très rarement!
Donc, tout le monde aurait marqué sur ce problème («acheter encore plus de RAM, ce qui est comme un voyou!»), Sinon un mais - il y a toutes sortes de nuages et de conteneurs dans lesquels cela signifie une utilisation insuffisante et une perte d'argent sérieuse. Regardez, quel rapport cool , rempli à ras bord de douleur.
La solution était d'apprendre à G1 à bien se comporter dans ce cas particulier, comme le savent déjà Shenanda ou GenCon d'OpenJ9. Il est nécessaire de déterminer l'utilisation insuffisante de la hanche et, en conséquence, de réduire son utilisation. Sur certains tests sur Tomcat, cela a permis de réduire de près de moitié la consommation de mémoire.
L'essentiel est que l'application est considérée comme inactive, ou si l'intervalle (en millisecondes) s'est getloadavg()
depuis la dernière génération et qu'il n'y a pas de cycle simultané, ou si getloadavg()
pendant une période d'une minute a montré une charge inférieure à un certain seuil. Dès que l'un de ces événements se produit, la collecte périodique des ordures démarre - elle ne nettoiera certainement pas aussi bien que l'assemblage complet, mais cela affectera l'application de manière minimale.
Vous pouvez le pousser dans ce journal:
(1) [6.084s][debug][gc,periodic ] Checking for periodic GC. [6.086s][info ][gc ] GC(13) Pause Young (Concurrent Start) (G1 Periodic Collection) 37M->36M(78M) 1.786ms (2) [9.087s][debug][gc,periodic ] Checking for periodic GC. [9.088s][info ][gc ] GC(15) Pause Young (Prepare Mixed) (G1 Periodic Collection) 9M->9M(32M) 0.722ms (3) [12.089s][debug][gc,periodic ] Checking for periodic GC. [12.091s][info ][gc ] GC(16) Pause Young (Mixed) (G1 Periodic Collection) 9M->5M(32M) 1.776ms (4) [15.092s][debug][gc,periodic ] Checking for periodic GC. [15.097s][info ][gc ] GC(17) Pause Young (Mixed) (G1 Periodic Collection) 5M->1M(32M) 4.142ms (5) [18.098s][debug][gc,periodic ] Checking for periodic GC. [18.100s][info ][gc ] GC(18) Pause Young (Concurrent Start) (G1 Periodic Collection) 1M->1M(32M) 1.685ms (6) [21.101s][debug][gc,periodic ] Checking for periodic GC. [21.102s][info ][gc ] GC(20) Pause Young (Concurrent Start) (G1 Periodic Collection) 1M->1M(32M) 0.868ms (7) [24.104s][debug][gc,periodic ] Checking for periodic GC. [24.104s][info ][gc ] GC(22) Pause Young (Concurrent Start) (G1 Periodic Collection) 1M->1M(32M) 0.778ms
Compris? Non. Dans JEP, il y a une traduction détaillée en langue des signes de chaque ligne du journal, et comment l'algorithme fonctionne, et tout le reste.
"Alors quoi, pourquoi ai-je découvert?" - demandez-vous. Nous avons maintenant deux poignées supplémentaires: G1PeriodicGCInterval
et G1PeriodicGCSystemLoadThreshold
, qui peuvent être tordues en cas de G1PeriodicGCSystemLoadThreshold
. C'est sûr que ça va être mauvais un jour, c'est Java, bébé!
Résumé
En conséquence, nous avons une version solide entre nos mains - pas une révolution, mais une évolution axée sur l'amélioration des performances. Exactement la moitié des améliorations sont liées aux performances: trois JEP sur GC et un sur CDS, qui promettent de s'activer par eux-mêmes, n'ont besoin que d'une mise à niveau vers JDK 12. En outre, nous avons une fonction de langue (expressions de commutateur), deux nouveaux outils pour les développeurs JDK ( Constantes API et tests JMH), et maintenant la communauté peut mieux se concentrer sur un seul port 64 bits sur ARM.
En général, passez à JDK 12 maintenant, et que la Force soit avec vous. Vous en aurez besoin.
Minute de publicité. Très prochainement, du 5 au 6 avril, se tiendra la conférence JPoint, qui réunira un grand nombre de personnes qui connaissent bien JDK et toutes sortes de nouvelles fonctionnalités. Par exemple, il y aura sûrement Simon Ritter d'Azul avec une conférence sur «JDK 12: pièges pour les imprudents» . L'endroit le plus approprié pour discuter de la dernière version! Vous pouvez en savoir plus sur JPoint sur le site officiel .