Java 13で、読み込み済みのクラスデータを終了時に保存するDynamic CDSが導入されました。
https://openjdk.java.net/jeps/350
で、試してみたら結構起動速度が変わっていました。
Micronautで試してみます。
準備
インストールは全部SDKMAN!で行います。(Windowsの場合はCygwinかWSLを使います)
$ curl -s "https://get.sdkman.io" | bash
ターミナルを開き直すとSDKMAN!が使えるようになります。
まずはJDKを。Micronautは現時点ではJDK13でビルドできないので、JDK12を使います。
$ sdk use java 12.0.2-open
次にMicronautをインストールします。
$ sdk use micronaut 1.2.4
Micronautのアプリケーションを作成します。
$ mn create-app myapp
できたフォルダに移動。
$ cd myapp
ビルドします。テストでこけることがあるので、テストをスキップ。
$ ./gradlew -x test build
実行してみます。
$ java -jar build/libs/myapp-0.1.jar 21:02:22.782 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 1103ms. Server Running: http://localhost:8080
終了はctrl+cで。
Dynamic CDSを試してみる
Dynamic CDSでクラスデータを保存するときは-XX:ArchiveClassesAtExit
をつけてアーカイブファイル名を指定します。
$ java -XX:ArchiveClassesAtExit=mn.jsa -jar build/libs/myapp-0.1.jar myapp $ java -XX:ArchiveClassesAtExit=mn.jsa -jar build/libs/myapp-0.1.jar 22:09:12.011 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 1681ms. Server Running: http://localhost:8080 ^C22:09:14.530 [Thread-2] INFO io.micronaut.runtime.Micronaut - Embedded Application shutting down [4.593s][warning][cds] Skipping io/micronaut/http/client/$DefaultHttpClientConfiguration$DefaultConnectionPoolConfigurationDefinition: Not linked [4.593s][warning][cds] Skipping io/reactivex/internal/operators/mixed/ObservableSwitchMapCompletable: Not linked [4.593s][warning][cds] Skipping io/reactivex/internal/operators/completable/CompletableTimeout: Not linked ...
18MBのファイルができています。
$ ls -l -h mn.jsa -r--r--r-- 1 kishida staff 18M 10 17 22:09 mn.jsa
このシェア用アーカイブファイルを利用するときは-XX:SharedArchiveFile
をつけてアーカイブファイルを指定します。
$ java -XX:SharedArchiveFile=mn.jsa -jar build/libs/myapp-0.1.jar
結果はあとでまとめますが、結構起動が速くなりました。
結果
ということで結果です。
Javaの標準クラスに関してはDefault CDSとしてJDK12から用意されるようになっていますが、これを使わないものも試してみました。
-Xshare:off
をつけるとDefault CDSファイルが使われなくなります。
$ java -Xshare:off -jar build/libs/myapp-0.1.jar
もうひとつ、Java 9から導入されているAOTも試してみます。今回はjava.baseモジュールだけAOTをかけてみます。
$ jaotc --output=libjava.base.so --module java.base
これを使うときは-XX:AOTLibrary
をつけてライブラリファイルを指定します。
$ java -XX:AOTLibrary=./libjava.base.so -XX:SharedArchiveFile=mn.jsa -jar build/libs/myapp-0.1.jar
6回連続で起動して2番目以降の平均を計測値にします。
また、Micronautの起動時間はmainメソッド以降の実行時間なので、mainメソッドの最初に
System.out.println(ManagementFactory.getRuntimeMXBean().getUptime());
をつけてJVM自体の起動時間も計測します。
JVM起動 | アプリケーション起動 | |
---|---|---|
No CDS | 149.6 | 1028.6 |
Default CDS | 98.6 | 1009.2 |
Dynamic CDS | 89.2 | 688.8 |
AOT+DynCDS | 144 | 625.6 |
ということでこんな結果に。
Default CDSではアプリケーション起動時間はあまり変わりませんがJVMの起動時間が短くなっています。そしてDynamic CDSでアプリケーションのクラスデータも再利用すると、アプリケーション起動時間がかなり縮まっていますね。
残念なのはAOTで、アプリケーション起動時間が縮まっているけどJVM起動時間がすこしのびて、トータルでは結局同じくらいの起動時間になっています。