Bonjour, Habr! À la lumière des nouvelles les plus récentes sur la politique d'Oracle concernant les licences Java, le problème de l'abandon des versions Oracle vers
OpenJDK devient de plus en plus aigu. Odanko dans OracleLabs fait depuis longtemps une chose très cool appelée
GraalVM , qui est un compilateur
JIT cool écrit en Java, ainsi qu'un runtime pour exécuter du code dans des langages tels que JavaScript, Ruby, Python, C, C ++, Scala, Kotlin, R, Clojure. Impressionnant, non? Mais pas au sujet de la fraîcheur de l'environnement polyglotte, je veux vous dire. Nous parlerons des difficultés de combiner le dernier assemblage Graal dans l'écosystème OpenJDK 11, et un peu de performance, un peu ...
Le premier était le mot
L'histoire de ma connaissance de
graalvm a commencé sur le
joker en 2017. Là,
Chris Seaton a parlé en détail des composants internes du compilateur et a montré la magie de la compilation
AOT en utilisant l'image native de la livraison du Graal comme exemple (c'est une blague qui compile votre code Java dans un binaire natif).
Après ce rapport, je me suis entraîné pendant très longtemps à compiler le binaire natif de mon projet pour animaux de compagnie, à mettre des béquilles et des râteaux afin de gagner de la réflexion dans tous les endroits (que ce ne soit pas bien!) Et finalement je suis tombé sur des problèmes non résolus avec IO (quelque chose là ça n'a pas décollé avec un gardien de zoo, maintenant je ne me souviens plus quoi). Crachez sur l'image native :-(
Année 2018, tout le même joker et le même graalvm dans un rapport super détaillé d'Oleg Shelaev sur AOT.
Dans les rapports et les présentations, tout a l'air si cool, et il y a aussi un projet animal sur le disque ... il est temps de découvrir le terminal, de balancer un nouveau candidat à la sortie du Graal et de se battre! Nous toucherons le jit.
Bonjour tout le monde
Toucher et frapper un petit JIT frais (au moment d'écrire cet article est la version
ce-1.0.0-rc14 ), nous utiliserons un morceau de code pour tester les performances du site
https://graalvm.org comme exemple - notre premier exemple.
Quel projet java (même
Hello World ) fait sans aucun système de build? C'est vrai, seul celui sur lequel javac apprend à cuisiner. Javak nous n'étudierons pas pour cuisiner, laissez maven diriger le javak.
Alors rencontrez pom.xml:
pom.xml<?xml version="1.0"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany.app</groupId> <artifactId>my-app</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>my-app</name> <url>http://maven.apache.org</url> <properties> <java.version>11</java.version> <graalvm.version>1.0.0-rc14</graalvm.version> </properties> <profiles> <profile> <id>jdk11</id> <activation> <jdk>11</jdk> </activation> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.10</version> <executions> <execution> <id>copy</id> <phase>process-test-classes</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <mainClass>com.mycompany.app.App</mainClass> </manifest> </archive> </configuration> </plugin> </plugins> </build> </profile> </profiles> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <release>${java.version}</release> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.graalvm.compiler</groupId> <artifactId>compiler</artifactId> <version>${graalvm.version}</version> </dependency> <dependency> <groupId>org.graalvm.truffle</groupId> <artifactId>truffle-api</artifactId> <version>${graalvm.version}</version> </dependency> <dependency> <groupId>org.graalvm.sdk</groupId> <artifactId>graal-sdk</artifactId> <version>${graalvm.version}</version> </dependency> <dependency> <groupId>org.graalvm.js</groupId> <artifactId>js</artifactId> <version>${graalvm.version}</version> </dependency> <dependency> <groupId>org.graalvm.js</groupId> <artifactId>js-scriptengine</artifactId> <version>${graalvm.version}</version> </dependency> </dependencies> </project>
La structure du fichier projet ressemble à ceci:

Code de classe
com.mycompany.app.App (exemple de copier-coller de graalvm.org):
App.java package com.mycompany.app; public class App { static final int ITERATIONS = Math.max(Integer.getInteger("iterations", 1), 1); public static void main(String[] args) { String sentence = String.join(" ", args); for (int iter = 0; iter < ITERATIONS; iter++) { if (ITERATIONS != 1) System.out.println("-- iteration " + (iter + 1) + " --"); long total = 0, start = System.currentTimeMillis(), last = start; for (int i = 1; i < 10_000_000; i++) { total += sentence.chars().filter(Character::isUpperCase).count(); if (i % 1_000_000 == 0) { long now = System.currentTimeMillis(); System.out.printf("%d (%d ms)%n", i / 1_000_000, now - last); last = now; } } System.out.printf("total: %d (%d ms)%n", total, System.currentTimeMillis() - start); } } }
Code
module-info.java :
module-info.java module com.mycompany.app {}
Hmm, vide ... Mais c'est vide pour la raison que je veux vous montrer comment java personnalisé (à propos de java personnalisé un peu plus tard) jurera avec les modules non déclarés dont notre application a besoin.
La première crêpe ...
pas grumeleux. Assemblons notre projet et lançons-le. Autrement dit:
mvn clean package
Nous lançons:
$JAVA_HOME/bin/java -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -Diterations=10 -jar target/my-app-1.0-SNAPSHOT.jar In 2017 I would like to run ALL languages in one VM.
Il y a deux points importants ici:
JVMCI est une chose expérimentale qui est apparue en Java depuis la version 9, nous avons donc besoin de:
Résultat de lancement- itération 1 - 1 (1466 ms)
2 (461 ms)
3 (463 ms)
4 (138 ms)
5 (151 ms)
6 (159 ms)
7 (266 ms)
8 (128 ms)
9 (144 ms)
total: 69999993 (3481 ms)
- itération 2-1 (233 ms)
2 (169 ms)
3 (121 ms)
4 (205 ms)
5 (170 ms)
6 (152 ms)
7 (227 ms)
8 (158 ms)
9 (108 ms)
total: 69999993 (1644 ms)
- itération 3 - 1 (98 ms)
2 (102 ms)
3 (98 ms)
4 (102 ms)
5 (95 ms)
6 (96 ms)
7 (101 ms)
8 (95 ms)
9 (97 ms)
total: 69999993 (990 ms)
- itération 4-1 (109 ms)
2 (114 ms)
3 (97 ms)
4 (98 ms)
5 (100 ms)
6 (103 ms)
7 (125 ms)
8 (108 ms)
9 (100 ms)
total: 69999993 (1056 ms)
- itération 5 - 1 (98 ms)
2 (100 ms)
3 (105 ms)
4 (97 ms)
5 (95 ms)
6 (99 ms)
7 (95 ms)
8 (123 ms)
9 (98 ms)
total: 69999993 (1010 ms)
- itération 6-1 (99 ms)
2 (95 ms)
3 (102 ms)
4 (99 ms)
5 (96 ms)
6 (100 ms)
7 (99 ms)
8 (99 ms)
9 (104 ms)
total: 69999993 (993 ms)
- itération 7-1 (100 ms)
2 (104 ms)
3 (95 ms)
4 (96 ms)
5 (97 ms)
6 (95 ms)
7 (94 ms)
8 (108 ms)
9 (108 ms)
total: 69999993 (1000 ms)
- itération 8-1 (100 ms)
2 (106 ms)
3 (99 ms)
4 (95 ms)
5 (97 ms)
6 (97 ms)
7 (101 ms)
8 (99 ms)
9 (101 ms)
total: 69999993 (1012 ms)
- itération 9-1 (105 ms)
2 (97 ms)
3 (98 ms)
4 (96 ms)
5 (99 ms)
6 (96 ms)
7 (94 ms)
8 (98 ms)
9 (105 ms)
total: 69999993 (993 ms)
- itération 10-1 (107 ms)
2 (98 ms)
3 (99 ms)
4 (100 ms)
5 (97 ms)
6 (101 ms)
7 (98 ms)
8 (103 ms)
9 (105 ms)
total: 69999993 (1006 ms)
Que voyons-nous ici? Et on voit que la première itération est la plus longue (3,5 secondes), ce JIT se réchauffe. Et puis tout est plus ou moins fluide (en une seconde).
Mais que faire si nous donnons à Java une nouvelle version du Graal? Aussitôt dit, aussitôt fait:
java -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -Diterations=10 --module-path=target/lib --upgrade-module-path=target/lib/compiler-1.0.0-rc14.jar -jar target/my-app-1.0-SNAPSHOT.jar In 2017 I would like to run ALL languages in one VM.
Résultat du lancement du Graal- itération 1 - 1 (1789 ms)
2 (547 ms)
3 (313 ms)
4 (87 ms)
5 (88 ms)
6 (87 ms)
7 (83 ms)
8 (92 ms)
9 (87 ms)
total: 69999993 (3259 ms)
- itération 2-1 (241 ms)
2 (161 ms)
3 (152 ms)
4 (195 ms)
5 (136 ms)
6 (129 ms)
7 (154 ms)
8 (176 ms)
9 (109 ms)
total: 69999993 (1553 ms)
- itération 3 - 1 (109 ms)
2 (103 ms)
3 (113 ms)
4 (172 ms)
5 (141 ms)
6 (148 ms)
7 (111 ms)
8 (102 ms)
9 (101 ms)
total: 69999993 (1211 ms)
- itération 4-1 (96 ms)
2 (96 ms)
3 (104 ms)
4 (98 ms)
5 (96 ms)
6 (97 ms)
7 (98 ms)
8 (96 ms)
9 (95 ms)
total: 69999993 (972 ms)
- itération 5 - 1 (97 ms)
2 (93 ms)
3 (99 ms)
4 (97 ms)
5 (97 ms)
6 (97 ms)
7 (95 ms)
8 (98 ms)
9 (94 ms)
total: 69999993 (965 ms)
- itération 6-1 (96 ms)
2 (95 ms)
3 (96 ms)
4 (99 ms)
5 (102 ms)
6 (94 ms)
7 (99 ms)
8 (115 ms)
9 (109 ms)
total: 69999993 (1001 ms)
- itération 7-1 (98 ms)
2 (96 ms)
3 (99 ms)
4 (98 ms)
5 (118 ms)
6 (98 ms)
7 (95 ms)
8 (99 ms)
9 (116 ms)
total: 69999993 (1017 ms)
- itération 8-1 (95 ms)
2 (99 ms)
3 (99 ms)
4 (106 ms)
5 (101 ms)
6 (101 ms)
7 (93 ms)
8 (97 ms)
9 (108 ms)
total: 69999993 (993 ms)
- itération 9-1 (102 ms)
2 (95 ms)
3 (97 ms)
4 (125 ms)
5 (94 ms)
6 (101 ms)
7 (100 ms)
8 (95 ms)
9 (96 ms)
total: 69999993 (1008 ms)
- itération 10-1 (97 ms)
2 (97 ms)
3 (99 ms)
4 (112 ms)
5 (102 ms)
6 (96 ms)
7 (96 ms)
8 (98 ms)
9 (96 ms)
total: 69999993 (988 ms)
Le résultat, comme nous le voyons, n'est pas très différent.
J'ai oublié. Eh bien, nous n'avons pas essayé d'exécuter la même chose sans le nouveau compilateur JIT. Nous ferons:
java -Diterations=10 -jar target/my-app-1.0-SNAPSHOT.jar In 2017 I would like to run ALL languages in one VM.
Résultat sans un nouveau compilateur JIT- itération 1 - 1 (372 ms)
2 (271 ms)
3 (337 ms)
4 (391 ms)
5 (328 ms)
6 (273 ms)
7 (239 ms)
8 (271 ms)
9 (250 ms)
total: 69999993 (2978 ms)
- itération 2 - 1 (242 ms)
2 (253 ms)
3 (253 ms)
4 (240 ms)
5 (245 ms)
6 (275 ms)
7 (273 ms)
8 (263 ms)
9 (234 ms)
total: 69999993 (2533 ms)
- itération 3-1 (237 ms)
2 (235 ms)
3 (234 ms)
4 (246 ms)
5 (242 ms)
6 (238 ms)
7 (244 ms)
8 (243 ms)
9 (253 ms)
total: 69999993 (2414 ms)
- itération 4-1 (244 ms)
2 (249 ms)
3 (245 ms)
4 (243 ms)
5 (232 ms)
6 (256 ms)
7 (321 ms)
8 (303 ms)
9 (249 ms)
total: 69999993 (2599 ms)
- itération 5 - 1 (246 ms)
2 (242 ms)
3 (248 ms)
4 (256 ms)
5 (280 ms)
6 (233 ms)
7 (235 ms)
8 (266 ms)
9 (246 ms)
total: 69999993 (2511 ms)
- itération 6-1 (292 ms)
2 (368 ms)
3 (339 ms)
4 (251 ms)
5 (267 ms)
6 (259 ms)
7 (289 ms)
8 (262 ms)
9 (357 ms)
total: 69999993 (3058 ms)
- itération 7-1 (284 ms)
2 (258 ms)
3 (248 ms)
4 (247 ms)
5 (266 ms)
6 (247 ms)
7 (242 ms)
8 (314 ms)
9 (265 ms)
total: 69999993 (2656 ms)
- itération 8-1 (239 ms)
2 (238 ms)
3 (257 ms)
4 (282 ms)
5 (244 ms)
6 (261 ms)
7 (253 ms)
8 (295 ms)
9 (256 ms)
total: 69999993 (2575 ms)
- itération 9-1 (273 ms)
2 (243 ms)
3 (239 ms)
4 (240 ms)
5 (250 ms)
6 (285 ms)
7 (266 ms)
8 (285 ms)
9 (264 ms)
total: 69999993 (2617 ms)
- itération 10-1 (245 ms)
2 (264 ms)
3 (258 ms)
4 (253 ms)
5 (239 ms)
6 (260 ms)
7 (251 ms)
8 (250 ms)
9 (256 ms)
total: 69999993 (2538 ms)
Le résultat est différent et décent.
C2 ne fournit aucune optimisation dans les morceaux chauds de code - chaque itération avec le même temps.
Graal est capable d'optimiser des morceaux de code chauds et à long terme donne une bonne amélioration des performances.
Et alors?
C'est peut-être la principale question que vous devez vous poser et poser aux autres (membres de l'équipe) lorsque nous voulons ajouter une nouvelle fonctionnalité au projet, un nouvel outil, une nouvelle machine virtuelle, un nouveau JIT ...
Mon histoire, comme décrit ci-dessus, a commencé avec Joker 2017, puis il y a eu de longues tentatives pour maîtriser AOT, et maintenant je goûte aux délices de JIT pour Java en Java.
Un projet favori sur disque est une sorte de moteur de processus métier, où les processus sont dessinés par les développeurs d'applications dans l'interface utilisateur du navigateur, et ils ont la possibilité d'écrire des scripts dans JS qui s'exécuteront sur la JVM.
Dans les futures versions de Java, ils promettent de supprimer nashorn, GraalVM approche progressivement de la sortie ...
Eh bien, la réponse à la question est la suivante:
- nous voulons qu'un runtime exécute JS (et pas seulement)
- je veux de la vitesse
- nous voulons que le lancement des applications de projets pour animaux de compagnie apparaisse comme auparavant sur 8 touches (sans
--module-path
et --upgrade-module-path
mais avec un assemblage de graal frais)
Jlink
Les deux premiers points de la liste des réponses à la question ci-dessus sont suffisamment clairs, examinons cette dernière.
Le fait est que les développeurs-administrateurs-devops sont paresseux et n'aiment pas faire de travail supplémentaire (j'aime ça aussi), ils essaient d'automatiser tout et de le regrouper dans un bundle prêt à l'emploi qui peut être exécuté comme un simple binaire. Eh bien, il y a un problème, résolvons-le.
Un outil relativement nouveau du monde de Java 9+ vient à notre aide, et son nom est
jlink . Nous essayons de regrouper notre application avec toutes les bibliothèques nécessaires dans un bundle:
jlink --module-path target/classes:target/lib:$JAVA_HOME/jmods --add-modules com.mycompany.app --launcher app=com.mycompany.app/com.mycompany.app.App --compress 2 --no-header-files --no-man-pages --strip-debug --output test
Combien de paramètres de tous, nous décrivons les principaux:
--module-path target / classes: target / lib: $ JAVA_HOME / jmods
--add-modules com.mycompany.app
--launcher app = com.mycompany.app / com.mycompany.app.App
- test de sortie
Vous pouvez demander à l'oncle de Google d'autres paramètres, tous visent à réduire la taille totale de l'ensemble.
Regardons le résultat:

À l'intérieur de test / bin / app, il y a un simple sh-script qui lance notre application sur Java qui se trouve à côté de l'application:
Exécutez
test / bin / app sur C2:
./test/bin/app In 2017 I would like to run ALL languages in one VM.
Résultat- itération 1 - 1 (315 ms)
2 (231 ms)
3 (214 ms)
4 (297 ms)
5 (257 ms)
6 (211 ms)
7 (217 ms)
8 (245 ms)
9 (222 ms)
total: 69999993 (2424 ms)
- itération 2 - 1 (215 ms)
2 (215 ms)
3 (223 ms)
4 (224 ms)
5 (217 ms)
6 (208 ms)
7 (208 ms)
8 (222 ms)
9 (222 ms)
total: 69999993 (2164 ms)
- itération 3 - 1 (206 ms)
2 (226 ms)
3 (234 ms)
4 (211 ms)
5 (212 ms)
6 (213 ms)
7 (210 ms)
8 (245 ms)
9 (223 ms)
total: 69999993 (2216 ms)
- itération 4-1 (222 ms)
2 (233 ms)
3 (220 ms)
4 (222 ms)
5 (221 ms)
6 (219 ms)
7 (222 ms)
8 (216 ms)
9 (220 ms)
total: 69999993 (2215 ms)
- itération 5-1 (231 ms)
2 (230 ms)
3 (221 ms)
4 (226 ms)
5 (227 ms)
6 (223 ms)
7 (215 ms)
8 (216 ms)
9 (219 ms)
total: 69999993 (2234 ms)
- itération 6-1 (227 ms)
2 (218 ms)
3 (221 ms)
4 (254 ms)
5 (222 ms)
6 (212 ms)
7 (214 ms)
8 (222 ms)
9 (222 ms)
total: 69999993 (2241 ms)
- itération 7-1 (217 ms)
2 (225 ms)
3 (222 ms)
4 (223 ms)
5 (227 ms)
6 (221 ms)
7 (219 ms)
8 (226 ms)
9 (219 ms)
total: 69999993 (2217 ms)
- itération 8-1 (218 ms)
2 (242 ms)
3 (219 ms)
4 (218 ms)
5 (224 ms)
6 (226 ms)
7 (223 ms)
8 (220 ms)
9 (219 ms)
total: 69999993 (2228 ms)
- itération 9-1 (234 ms)
2 (218 ms)
3 (217 ms)
4 (217 ms)
5 (225 ms)
6 (222 ms)
7 (216 ms)
8 (226 ms)
9 (214 ms)
total: 69999993 (2212 ms)
- itération 10-1 (226 ms)
2 (230 ms)
3 (215 ms)
4 (238 ms)
5 (225 ms)
6 (218 ms)
7 (218 ms)
8 (215 ms)
9 (228 ms)
total: 69999993 (2233 ms)
Maintenant sur graalvm (en définissant les drapeaux nécessaires à exécuter dans la variable
JLINK_VM_OPTIONS ):
Résultat:
Error occurred during initialization of boot layer java.lang.module.FindException: Module jdk.internal.vm.ci not found
Eh bien, nous avons navigué ... Et maintenant, nous nous souvenons que nous travaillons avec java 11 dans un environnement modulaire, nous construisons l'application en tant que module, mais ils n'ont parlé à personne des modules utilisés. Il est temps de le réparer.
Nouvelle version de module-info.java:
module com.mycompany.app { requires jdk.internal.vm.compiler; requires org.graalvm.sdk; requires org.graalvm.truffle; requires transitive org.graalvm.js; requires transitive org.graalvm.js.scriptengine; }
Nous collectons , supprimons le répertoire de test, le
lien .
Résultat:
Error: automatic module cannot be used with jlink: icu4j from file:///home/slava/JavaProjects/graal-js-jdk11-maven-demo/target/lib/icu4j-62.1.jar
Quel genre de «module automatique kennote bi uzd»? Et ce
jlink nous dit que la
lib icu4j ne contient pas module-info.class. Ce qui est nécessaire pour qu'une telle classe apparaisse dans la lib spécifiée:
- comprendre la liste des modules utilisés par any et créer module-info.java , définir tous les packages qui doivent être visibles de l'extérieur
- compiler module-info.java pour
- mettre le module-info.java compilé dans le dzharnik avec tout
C'est parti!
Le fichier module-info.java avec tout son contenu générera pour
nous l' utilitaire jdeps de openjdk-11:

Nous compilons module-info.java pour icu4j:

Nous mettons à jour le dzharnik en y poussant
module-info.class :
$JAVA_HOME/bin/jar uf target/lib/icu4j-62.1.jar -C target/modules module-info.class
Lien ,
exécutez .
Résultat- itération 1 - 1 (1216 ms)
2 (223 ms)
3 (394 ms)
4 (138 ms)
5 (116 ms)
6 (102 ms)
7 (120 ms)
8 (106 ms)
9 (110 ms)
total: 69999993 (2619 ms)
- itération 2-1 (166 ms)
2 (133 ms)
3 (142 ms)
4 (157 ms)
5 (119 ms)
6 (134 ms)
7 (153 ms)
8 (95 ms)
9 (85 ms)
total: 69999993 (1269 ms)
- itération 3 - 1 (86 ms)
2 (81 ms)
3 (87 ms)
4 (83 ms)
5 (85 ms)
6 (100 ms)
7 (87 ms)
8 (83 ms)
9 (85 ms)
total: 69999993 (887 ms)
- itération 4-1 (84 ms)
2 (86 ms)
3 (88 ms)
4 (91 ms)
5 (85 ms)
6 (88 ms)
7 (87 ms)
8 (85 ms)
9 (85 ms)
total: 69999993 (864 ms)
- itération 5 - 1 (94 ms)
2 (86 ms)
3 (84 ms)
4 (83 ms)
5 (85 ms)
6 (86 ms)
7 (84 ms)
8 (84 ms)
9 (83 ms)
total: 69999993 (854 ms)
- itération 6-1 (83 ms)
2 (89 ms)
3 (87 ms)
4 (87 ms)
5 (86 ms)
6 (86 ms)
7 (91 ms)
8 (86 ms)
9 (85 ms)
total: 69999993 (865 ms)
- itération 7-1 (87 ms)
2 (86 ms)
3 (88 ms)
4 (90 ms)
5 (91 ms)
6 (87 ms)
7 (85 ms)
8 (85 ms)
9 (86 ms)
total: 69999993 (868 ms)
- itération 8-1 (84 ms)
2 (85 ms)
3 (86 ms)
4 (84 ms)
5 (84 ms)
6 (88 ms)
7 (85 ms)
8 (86 ms)
9 (86 ms)
total: 69999993 (852 ms)
- itération 9-1 (83 ms)
2 (85 ms)
3 (84 ms)
4 (85 ms)
5 (89 ms)
6 (85 ms)
7 (88 ms)
8 (86 ms)
9 (83 ms)
total: 69999993 (850 ms)
- itération 10-1 (83 ms)
2 (84 ms)
3 (83 ms)
4 (82 ms)
5 (85 ms)
6 (83 ms)
7 (84 ms)
8 (94 ms)
9 (93 ms)
total: 69999993 (856 ms)
Vive! Nous l'avons fait! Nous avons maintenant une application interdite sous la forme d'un sh-script en cours d'exécution avec notre Java, avec tous les modules nécessaires (y compris le graalvm frais), de préférence et les jeunes filles.
PS
Java ne s'ennuie pas et donne de nouveaux aliments à l'esprit à chaque version. Essayez de nouvelles fonctionnalités, expérimentez, partagez votre expérience. J'espère que j'écrirai bientôt un article sur la façon dont j'ai interdit une partie du projet pour animaux de compagnie avec le Graal (il y a vert.x, l'asynchronisme et les scripts js - ce sera intéressant).
Et pourtant ... c'est mon premier article sur Habré, - s'il vous plaît, ne frappez pas fort.