Java 13で、読み込み済みのクラスデータを終了時に保存するDynamic CDSが導入されました。
https://openjdk.java.net/jeps/350
で、試してみたら結構起動速度が変わっていました。
Micronautで試してみます。
追記: Java 10でApplication Class-Data Sharingが入っているので、自分でクラスリストを作ってダンプすれば同等のことができていたのだけど、面倒さが低減された感じです。LTSであるJava 11ではAppCDSを使うといいと思います。
追記2: 自分でダンプしたほうがかなり速かった
Dynamic CDSよりJava10からある自力ダンプの方が起動が速い - きしだのHatena
準備
インストールは全部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自体の起動時間も計測しています。
package myapp; import io.micronaut.runtime.Micronaut; import java.lang.management.ManagementFactory; public class Application { public static void main(String[] args) { System.out.println(ManagementFactory.getRuntimeMXBean().getUptime()); Micronaut.run(Application.class); } }
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起動時間がすこしのびて、トータルでは結局同じくらいの起動時間になっています。