← Spring コース
59. 起動を速くする方向と失うもの
依存を中に入れた(fat JAR)は、起動のたびにの読み込みと 集めを行います( の起動と、 の回)。この仕事を前倒しするほど起動は短くなりました。自己申告の起動時間は、fat JAR 約0.6秒、 をほどいて置く展開で約0.54秒、で約0.25秒、 再起動後に別環境で測った で約0.04秒です。
名前の似た2つは別物です。AOT キャッシュは JVM の機能で、学習用に1回走らせてクラスの読み込み結果を約53MBのファイルに残します。 は がビルド時に Bean 定義のコードを生成する仕組みです。native image は JVM を持たない実行ファイルで、ビルドは66〜68秒、ピークメモリは4.18〜4.29GB、実行時にクラスは足せず、残るの対象は事前に申告します。
期待と違う結果もありました。リファレンスは AOT キャッシュがメモリの削減にも役立つと書きますが、この測り方ではアイドル時の (実メモリ使用量)は288〜304MBで、無しの265〜287MBより減りませんでした。また fat JAR のままキャッシュを指定しても効きません。どれも がほぼ無いアプリの値で、起動後の処理性能は測っていません。
点線の付いた語はタップすると説明が出ます。用語集を開く →
fat JAR(実行可能 JAR)のまま0.599〜0.637 秒
入れ子の JAR をローダ経由で読むJAR を展開しておく
展開0.534〜0.551 秒
払うもの: 配るものが1ファイルでなくなるクラスの読み込み結果を持ち越す
展開 + CDS0.354〜0.370 秒
払うもの: 学習用の実行、約32MBのファイル展開 + AOT キャッシュ0.252〜0.259 秒
払うもの: 学習用の実行、約53MBのファイル、JAR を変えたら作り直しBean 定義集めもビルド時に済ませる(Docker 再起動後の系列)
展開 + Spring AOT + AOT キャッシュ0.176〜0.204 秒
払うもの: どの Bean を作るかがビルド時に固定されるJVM を持たない実行ファイルにする
native image0.035〜0.045 秒
払うもの: ビルド 66〜68秒・ピーク 4.18〜4.29GB、実行時にクラスを足せない- ・上の3段は同じ系列、Spring AOT と native image は Docker の再起動をはさんだ後の系列です(native image は最終イメージの中で測定)。厳密な横並びではありません
- ・AOT キャッシュ(JVM の機能)と Spring AOT(Spring がビルド時に行うコード生成)は、名前は似ていますが別物です
- ・CDS と AOT キャッシュは JVM がそのまま動くので、実行時にクラスを読み込む仕組みは失いません
- ・native image の成果物は 86,707,304 バイトで、fat JAR(約19.9MB)より大きくなりました。JRE は要りません
サンプルコード(フレームワーク環境が必要なため表示のみ)
// Spring AOT(spring-boot:process-aot)がビルド時に生成したソースの実物(Boot 4.1.1・全文)
// target/spring-aot/main/sources/com/example/demo/HelloController__BeanDefinitions.java
package com.example.demo;
import org.springframework.aot.generate.Generated;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
/**
* Bean definitions for {@link HelloController}.
*/
@Generated
public class HelloController__BeanDefinitions {
/**
* Get the bean definition for 'helloController'.
*/
public static BeanDefinition getHelloControllerBeanDefinition() {
RootBeanDefinition beanDefinition = new RootBeanDefinition(HelloController.class);
beanDefinition.setInstanceSupplier(HelloController::new);
return beanDefinition;
}
}
// 実行時にクラスパスを走査して @RestController を探す代わりに、
// ビルド時に見つけた結果が「HelloController::new を呼べ」という普通の Java コードになっている。
// この最小アプリで生成されたのは、Java ソース 53本、クラス 75個、
// reachability-metadata.json(147,945 バイト)と native-image.properties。
図やコードに出てくる用語(タップで説明)
サンプルコードで身につける(5本) →
学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。
公式ドキュメントで詳しく ↗