ハリネズミとハリネズミの交配:OpenJDK-11 + GraalVM

こんにちは、Habr! Javaライセンスに関するOracleのポリシーに関する最新のニュースではないため、OracleバージョンからOpenJDKへの移行の問題はますます深刻になっています。 OracleLabsのOdankoは、Javaで書かれたクールなJITコンパイラであるGraalVMと呼ばれる非常にクールなことを長い間行ってきました。また、JavaScript、Ruby、Python、C、C ++、Scala、Kotlinなどの言語でコードを実行するためのランタイム、 R、Clojure。 印象的でしょ? しかし、多言語環境のクールさについてではありません。 最新のgrailアセンブリをOpenJDK 11エコシステムに組み込むことの難しさ、およびパフォーマンスについて少し説明します。



最初は言葉でした



graalvmについての私の知り合いの話は、2017年にジョーカーから始まりました。 そこで、 Chris Seatonがコンパイラの内部について詳しく説明し、例としてgrail配信からのネイティブイメージを使用したAOTコンパイルの魔法を示しました(これは、Javaコードをネイティブバイナリにコンパイルするジョークです)。



その報告の後、私はペットプロジェクトのネイティブバイナリをコンパイルするために非常に長い間訓練し、松葉杖と熊手を置いてあらゆる場所で反省を獲得しました(大丈夫ではありません!)そしてついにIOに関する未解決の問題(何か)につまずきましたそこでは、動物園の飼育係と一緒に離陸しませんでした。 native-imageで唾を吐く:-(



2018年、AOTに関するOleg Shelaevからの非常に詳細なレポートで、すべて同じジョーカーと同じgraalvm。



レポートとプレゼンテーションでは、すべてがとてもクールに見えます。また、ディスク上にペットプロジェクトがあります。ターミナルを発見し、新鮮な聖杯リリース候補を振り回して、戦いに行きましょう! jitに触れます。



ハローワールド



新鮮な小さなJIT(この記事の執筆時点ではバージョンce-1.0.0-rc14です )に触れてキックします 。サイトhttps://graalvm.orgからパフォーマンスをテストするためのコードの例を使用します -最初の例です。



ビルドシステムなしで実行しているJavaプロジェクト( Hello Worldを含む ) そう、javacが料理を学んでいる人だけです。 Javakは勉強しません。mavenがJavakを操縦します。



したがって、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>--> <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>
      
      







プロジェクトファイルの構造は次のようになります。







クラスコードcom.mycompany.app.Appgraalvm.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); } } }
      
      







module-info.javaのコード:



module-info.java
  module com.mycompany.app {}
      
      







うーん、空です...しかし、カスタムJava(カスタムJavaについて)が、アプリケーションに必要な未宣言のモジュールをどのように誓うかを説明したいので、空です。



最初のパンケーキ...



ゴツゴツしていません。 プロジェクトを組み立てて起動しましょう。 このように配置する:



 mvn clean package
      
      







以下を開始します。



 $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.
      
      





ここには2つの重要なポイントがあります。JVMCIは、バージョン9からJavaに登場した実験的なものであるため、次のものが必要です。





打ち上げ結果
-反復1-1(1466ミリ秒)

2(461ミリ秒)

3(463ミリ秒)

4(138ミリ秒)

5(151ミリ秒)

6(159ミリ秒)

7(266ミリ秒)

8(128ミリ秒)

9(144ミリ秒)

合計:69999993(3481ミリ秒)

-反復2-1(233ミリ秒)

2(169ミリ秒)

3(121ミリ秒)

4(205ミリ秒)

5(170ミリ秒)

6(152ミリ秒)

7(227ミリ秒)

8(158ミリ秒)

9(108ミリ秒)

合計:69999993(1644ミリ秒)

-反復3-1(98ミリ秒)

2(102ミリ秒)

3(98ミリ秒)

4(102ミリ秒)

5(95ミリ秒)

6(96ミリ秒)

7(101ミリ秒)

8(95ミリ秒)

9(97ミリ秒)

合計:69999993(990ミリ秒)

-反復4-1(109ミリ秒)

2(114ミリ秒)

3(97ミリ秒)

4(98ミリ秒)

5(100ミリ秒)

6(103ミリ秒)

7(125ミリ秒)

8(108ミリ秒)

9(100ミリ秒)

合計:69999993(1056ミリ秒)

-反復5-1(98ミリ秒)

2(100ミリ秒)

3(105ミリ秒)

4(97ミリ秒)

5(95ミリ秒)

6(99ミリ秒)

7(95ミリ秒)

8(123ミリ秒)

9(98ミリ秒)

合計:69999993(1010ミリ秒)

-反復6-1(99ミリ秒)

2(95ミリ秒)

3(102ミリ秒)

4(99ミリ秒)

5(96ミリ秒)

6(100ミリ秒)

7(99ミリ秒)

8(99ミリ秒)

9(104ミリ秒)

合計:69999993(993ミリ秒)

-反復7-1(100ミリ秒)

2(104ミリ秒)

3(95ミリ秒)

4(96ミリ秒)

5(97ミリ秒)

6(95ミリ秒)

7(94ミリ秒)

8(108ミリ秒)

9(108ミリ秒)

合計:69999993(1000ミリ秒)

-反復8-1(100ミリ秒)

2(106ミリ秒)

3(99ミリ秒)

4(95ミリ秒)

5(97ミリ秒)

6(97ミリ秒)

7(101ミリ秒)

8(99ミリ秒)

9(101ミリ秒)

合計:69999993(1012ミリ秒)

-反復9-1(105ミリ秒)

2(97ミリ秒)

3(98ミリ秒)

4(96ミリ秒)

5(99ミリ秒)

6(96ミリ秒)

7(94ミリ秒)

8(98ミリ秒)

9(105ミリ秒)

合計:69999993(993ミリ秒)

-反復10-1(107ミリ秒)

2(98ミリ秒)

3(99ミリ秒)

4(100ミリ秒)

5(97ミリ秒)

6(101ミリ秒)

7(98ミリ秒)

8(103ミリ秒)

9(105ミリ秒)

合計:69999993(1006ミリ秒)



ここで何が見えますか? そして、最初の反復が最も長く(3.5秒)、このJITがウォームアップしていることがわかります。 そして、すべてが多少スムーズです(1秒以内)。



Javaに新しいバージョンのgrailを提供するとどうなりますか? すぐに言ってやった:



 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.
      
      





新鮮な杯の打ち上げ結果
-反復1-1(1789ミリ秒)

2(547ミリ秒)

3(313ミリ秒)

4(87ミリ秒)

5(88ミリ秒)

6(87ミリ秒)

7(83ミリ秒)

8(92ミリ秒)

9(87ミリ秒)

合計:69999993(3259ミリ秒)

-反復2-1(241ミリ秒)

2(161ミリ秒)

3(152ミリ秒)

4(195ミリ秒)

5(136ミリ秒)

6(129ミリ秒)

7(154ミリ秒)

8(176ミリ秒)

9(109ミリ秒)

合計:69999993(1553ミリ秒)

-反復3-1(109ミリ秒)

2(103ミリ秒)

3(113ミリ秒)

4(172ミリ秒)

5(141ミリ秒)

6(148ミリ秒)

7(111ミリ秒)

8(102ミリ秒)

9(101ミリ秒)

合計:69999993(1211ミリ秒)

-反復4-1(96ミリ秒)

2(96ミリ秒)

3(104ミリ秒)

4(98ミリ秒)

5(96ミリ秒)

6(97ミリ秒)

7(98ミリ秒)

8(96ミリ秒)

9(95ミリ秒)

合計:69999993(972ミリ秒)

-反復5-1(97ミリ秒)

2(93ミリ秒)

3(99ミリ秒)

4(97ミリ秒)

5(97ミリ秒)

6(97ミリ秒)

7(95ミリ秒)

8(98ミリ秒)

9(94ミリ秒)

合計:69999993(965ミリ秒)

-反復6-1(96ミリ秒)

2(95ミリ秒)

3(96ミリ秒)

4(99ミリ秒)

5(102ミリ秒)

6(94ミリ秒)

7(99ミリ秒)

8(115ミリ秒)

9(109ミリ秒)

合計:69999993(1001ミリ秒)

-反復7-1(98ミリ秒)

2(96ミリ秒)

3(99ミリ秒)

4(98ミリ秒)

5(118ミリ秒)

6(98ミリ秒)

7(95ミリ秒)

8(99ミリ秒)

9(116ミリ秒)

合計:69999993(1017ミリ秒)

-反復8-1(95ミリ秒)

2(99ミリ秒)

3(99ミリ秒)

4(106ミリ秒)

5(101ミリ秒)

6(101ミリ秒)

7(93ミリ秒)

8(97ミリ秒)

9(108ミリ秒)

合計:69999993(993ミリ秒)

-反復9-1(102ミリ秒)

2(95ミリ秒)

3(97ミリ秒)

4(125ミリ秒)

5(94ミリ秒)

6(101ミリ秒)

7(100ミリ秒)

8(95ミリ秒)

9(96ミリ秒)

合計:69999993(1008ミリ秒)

-反復10-1(97ミリ秒)

2(97ミリ秒)

3(99ミリ秒)

4(112ミリ秒)

5(102ミリ秒)

6(96ミリ秒)

7(96ミリ秒)

8(98ミリ秒)

9(96ミリ秒)

合計:69999993(988ミリ秒)



ご覧のとおり、結果はそれほど変わりません。



忘れた 新しいJITコンパイラーなしでは同じことを実行しようとしませんでした。 行います:



 java -Diterations=10 -jar target/my-app-1.0-SNAPSHOT.jar In 2017 I would like to run ALL languages in one VM.
      
      





新規のJITコンパイラーなしの結果
-反復1-1(372ミリ秒)

2(271ミリ秒)

3(337ミリ秒)

4(391ミリ秒)

5(328ミリ秒)

6(273ミリ秒)

7(239ミリ秒)

8(271ミリ秒)

9(250ミリ秒)

合計:69999993(2978ミリ秒)

-反復2-1(242ミリ秒)

2(253ミリ秒)

3(253ミリ秒)

4(240ミリ秒)

5(245ミリ秒)

6(275ミリ秒)

7(273ミリ秒)

8(263ミリ秒)

9(234ミリ秒)

合計:69999993(2533ミリ秒)

-反復3-1(237ミリ秒)

2(235ミリ秒)

3(234ミリ秒)

4(246ミリ秒)

5(242ミリ秒)

6(238ミリ秒)

7(244ミリ秒)

8(243ミリ秒)

9(253ミリ秒)

合計:69999993(2414ミリ秒)

-反復4-1(244ミリ秒)

2(249ミリ秒)

3(245ミリ秒)

4(243ミリ秒)

5(232ミリ秒)

6(256ミリ秒)

7(321ミリ秒)

8(303ミリ秒)

9(249ミリ秒)

合計:69999993(2599ミリ秒)

-反復5-1(246ミリ秒)

2(242ミリ秒)

3(248ミリ秒)

4(256ミリ秒)

5(280ミリ秒)

6(233ミリ秒)

7(235ミリ秒)

8(266ミリ秒)

9(246ミリ秒)

合計:69999993(2511ミリ秒)

-反復6-1(292ミリ秒)

2(368ミリ秒)

3(339ミリ秒)

4(251ミリ秒)

5(267ミリ秒)

6(259ミリ秒)

7(289ミリ秒)

8(262ミリ秒)

9(357ミリ秒)

合計:69999993(3058ミリ秒)

-反復7-1(284ミリ秒)

2(258ミリ秒)

3(248ミリ秒)

4(247ミリ秒)

5(266ミリ秒)

6(247ミリ秒)

7(242ミリ秒)

8(314ミリ秒)

9(265ミリ秒)

合計:69999993(2656ミリ秒)

-反復8-1(239ミリ秒)

2(238ミリ秒)

3(257ミリ秒)

4(282ミリ秒)

5(244ミリ秒)

6(261ミリ秒)

7(253ミリ秒)

8(295ミリ秒)

9(256ミリ秒)

合計:69999993(2575ミリ秒)

-反復9-1(273ミリ秒)

2(243ミリ秒)

3(239ミリ秒)

4(240ミリ秒)

5(250ミリ秒)

6(285ミリ秒)

7(266ミリ秒)

8(285ミリ秒)

9(264ミリ秒)

合計:69999993(2617ミリ秒)

-反復10-1(245ミリ秒)

2(264ミリ秒)

3(258ミリ秒)

4(253ミリ秒)

5(239ミリ秒)

6(260ミリ秒)

7(251ミリ秒)

8(250ミリ秒)

9(256ミリ秒)

合計:69999993(2538ミリ秒)



結果は異なり、まともです。



C2は、ホットコードの最適化を提供しません-各反復が同時に実行されます。



Graalはホットなコードを最適化でき、長期的にはパフォーマンスが大幅に向上します。



それで何?



これはおそらく、プロジェクトに新しい機能、新しいツール、新しい仮想マシン、新しいJITを追加するときに、自分自身や他の人(チームメンバー)に尋ねる必要がある主な質問です...



上記のとおり、私の話はJoker 2017で始まり、その後AOTをマスターしようという長い試みがありましたが、今ではJavaでJIT for Javaの喜びを味わっています。



ディスク上のペットプロジェクトは一種のビジネスプロセスエンジンであり、ブラウザUIでアプリケーション開発者によってプロセスが描画され、JVMで実行されるJSでスクリプトを記述する機能があります。



Javaの将来のバージョンでは、nashornを削除することを約束し、GraalVMは徐々にリリースに近づいています...



さて、質問への答えはこれです:



  1. ランタイムにJSを実行させたい(だけでなく)
  2. スピードを上げたい
  3. ペットプロジェクトアプリケーションの起動を8-keで以前のように表示する(
      --module-path 
    そして
      --upgrade-module-path 
    ただし、新鮮な杯アセンブリを使用)


Jlink



上記の質問に対する回答のリストの最初の2つのポイントは十分に明確であるため、後者に対処しましょう。



実際、開発者、管理者、開発者は怠け者であり、余分な作業をするのは好きではありません(私もそうです)。 問題があります。解決しましょう。



Java 9+の世界からの比較的新しいツールが私たちの助けになります。その名前はjlinkです。 必要なすべてのライブラリをバンドルしてアプリケーションをパックしようとしています。



 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
      
      





すべての種類のパラメーターの数。主なものについて説明します。



残りのパラメーターについてはGoogleの叔父にお尋ねください。これらはすべて、バンドルの合計サイズを小さくすることを目的としています。



結果を見てみましょう:







テスト/ビン/アプリの内部には、アプリの隣にあるJavaでアプリケーションを起動する簡単なshスクリプトがあります。



 #!/bin/sh JLINK_VM_OPTIONS="-Diterations=10" #     ,       DIR=`dirname $0` $DIR/java $JLINK_VM_OPTIONS -m com.mycompany.app/com.mycompany.app.App $@
      
      





C2でtest / bin / appを実行します。



 ./test/bin/app In 2017 I would like to run ALL languages in one VM.
      
      





結果
-反復1-1(315ミリ秒)

2(231ミリ秒)

3(214ミリ秒)

4(297ミリ秒)

5(257ミリ秒)

6(211ミリ秒)

7(217ミリ秒)

8(245ミリ秒)

9(222ミリ秒)

合計:69999993(2424ミリ秒)

-反復2-1(215ミリ秒)

2(215ミリ秒)

3(223ミリ秒)

4(224ミリ秒)

5(217ミリ秒)

6(208ミリ秒)

7(208ミリ秒)

8(222ミリ秒)

9(222ミリ秒)

合計:69999993(2164ミリ秒)

-反復3-1(206ミリ秒)

2(226ミリ秒)

3(234ミリ秒)

4(211ミリ秒)

5(212ミリ秒)

6(213ミリ秒)

7(210ミリ秒)

8(245ミリ秒)

9(223ミリ秒)

合計:69999993(2216ミリ秒)

-反復4-1(222ミリ秒)

2(233ミリ秒)

3(220ミリ秒)

4(222ミリ秒)

5(221ミリ秒)

6(219ミリ秒)

7(222ミリ秒)

8(216ミリ秒)

9(220ミリ秒)

合計:69999993(2215ミリ秒)

-反復5-1(231ミリ秒)

2(230ミリ秒)

3(221ミリ秒)

4(226ミリ秒)

5(227ミリ秒)

6(223ミリ秒)

7(215ミリ秒)

8(216ミリ秒)

9(219ミリ秒)

合計:69999993(2234ミリ秒)

-反復6-1(227ミリ秒)

2(218ミリ秒)

3(221ミリ秒)

4(254ミリ秒)

5(222ミリ秒)

6(212ミリ秒)

7(214ミリ秒)

8(222ミリ秒)

9(222ミリ秒)

合計:69999993(2241ミリ秒)

-反復7-1(217ミリ秒)

2(225ミリ秒)

3(222ミリ秒)

4(223ミリ秒)

5(227ミリ秒)

6(221ミリ秒)

7(219ミリ秒)

8(226ミリ秒)

9(219ミリ秒)

合計:69999993(2217ミリ秒)

-反復8-1(218ミリ秒)

2(242ミリ秒)

3(219ミリ秒)

4(218ミリ秒)

5(224ミリ秒)

6(226ミリ秒)

7(223ミリ秒)

8(220ミリ秒)

9(219ミリ秒)

合計:69999993(2228ミリ秒)

-反復9-1(234ミリ秒)

2(218ミリ秒)

3(217ミリ秒)

4(217ミリ秒)

5(225ミリ秒)

6(222ミリ秒)

7(216ミリ秒)

8(226ミリ秒)

9(214ミリ秒)

合計:69999993(2212ミリ秒)

-反復10-1(226ミリ秒)

2(230ミリ秒)

3(215ミリ秒)

4(238ミリ秒)

5(225ミリ秒)

6(218ミリ秒)

7(218ミリ秒)

8(215ミリ秒)

9(228ミリ秒)

合計:69999993(2233ミリ秒)



graalvmで( JLINK_VM_OPTIONS変数で実行するために必要なフラグを定義することにより):



テスト/ビン/アプリ
 #!/bin/sh JLINK_VM_OPTIONS="-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler -Diterations=10" DIR=`dirname $0` $DIR/java $JLINK_VM_OPTIONS -m com.mycompany.app/com.mycompany.app.App $@
      
      







結果:



 Error occurred during initialization of boot layer java.lang.module.FindException: Module jdk.internal.vm.ci not found
      
      





さて、到着しました...そして、モジュール環境でJava 11を使用していることを思い出してください。アプリケーションをモジュールとして構築していますが、使用されているモジュールについては誰にも伝えませんでした。 それを修正する時が来ました。



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; }
      
      





テストディレクトリlink を収集 、削除します。



結果:



 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
      
      





どのような「自動モジュールkennote bi uzd」ですか? そして、このjlinkは、icu4j libに module-info.classが含まれていないことを示しています。 そのようなクラスが指定されたlib内に表示されるために必要なもの:





行こう!



すべての内容を含むmodule-info.javaファイルは、openjdk-11からjdepsユーティリティを生成します。







icu4jのmodule-info.javaをコンパイルします。







module-info.classをプッシュしてdzharnikを更新します。



 $JAVA_HOME/bin/jar uf target/lib/icu4j-62.1.jar -C target/modules module-info.class
      
      





リンク実行



結果
-反復1-1(1216ミリ秒)

2(223ミリ秒)

3(394ミリ秒)

4(138ミリ秒)

5(116ミリ秒)

6(102ミリ秒)

7(120ミリ秒)

8(106ミリ秒)

9(110ミリ秒)

合計:69999993(2619ミリ秒)

-反復2-1(166ミリ秒)

2(133ミリ秒)

3(142ミリ秒)

4(157ミリ秒)

5(119ミリ秒)

6(134ミリ秒)

7(153ミリ秒)

8(95ミリ秒)

9(85ミリ秒)

合計:69999993(1269ミリ秒)

-反復3-1(86ミリ秒)

2(81ミリ秒)

3(87ミリ秒)

4(83ミリ秒)

5(85ミリ秒)

6(100ミリ秒)

7(87ミリ秒)

8(83ミリ秒)

9(85ミリ秒)

合計:69999993(887ミリ秒)

-反復4-1(84ミリ秒)

2(86ミリ秒)

3(88ミリ秒)

4(91ミリ秒)

5(85ミリ秒)

6(88ミリ秒)

7(87ミリ秒)

8(85ミリ秒)

9(85ミリ秒)

合計:69999993(864ミリ秒)

-反復5-1(94ミリ秒)

2(86ミリ秒)

3(84ミリ秒)

4(83ミリ秒)

5(85ミリ秒)

6(86ミリ秒)

7(84ミリ秒)

8(84ミリ秒)

9(83ミリ秒)

合計:69999993(854ミリ秒)

-反復6-1(83ミリ秒)

2(89ミリ秒)

3(87ミリ秒)

4(87ミリ秒)

5(86ミリ秒)

6(86ミリ秒)

7(91ミリ秒)

8(86ミリ秒)

9(85ミリ秒)

合計:69999993(865ミリ秒)

-反復7-1(87ミリ秒)

2(86ミリ秒)

3(88ミリ秒)

4(90ミリ秒)

5(91ミリ秒)

6(87ミリ秒)

7(85ミリ秒)

8(85ミリ秒)

9(86ミリ秒)

合計:69999993(868ミリ秒)

-反復8-1(84ミリ秒)

2(85ミリ秒)

3(86ミリ秒)

4(84ミリ秒)

5(84ミリ秒)

6(88ミリ秒)

7(85ミリ秒)

8(86ミリ秒)

9(86ミリ秒)

合計:69999993(852ミリ秒)

-反復9-1(83ミリ秒)

2(85ミリ秒)

3(84ミリ秒)

4(85ミリ秒)

5(89ミリ秒)

6(85ミリ秒)

7(88ミリ秒)

8(86ミリ秒)

9(83ミリ秒)

合計:69999993(850ミリ秒)

-反復10-1(83ミリ秒)

2(84ミリ秒)

3(83ミリ秒)

4(82ミリ秒)

5(85ミリ秒)

6(83ミリ秒)

7(84ミリ秒)

8(94ミリ秒)

9(93ミリ秒)

合計:69999993(856ミリ秒)



ほら! やった! これで、必要なすべてのモジュール(新鮮なgraalvmを含む)、好み、若い女性を含む、Javaで実行中のshスクリプトの形式の禁止アプリケーションが作成されました。



PS



Javaは退屈することなく、リリースごとに心に新しい食べ物を提供します。 新機能を試し、実験し、経験を共有してください。 ペットプロジェクトの一部をどのように聖杯で禁止したかについての記事をすぐに書きたいと思います(vert.x、非同期性、jsスクリプトが興味深いでしょう)。



それでも...これはHabréについての私の最初の記事です-強く叩かないでください。



All Articles