Java 10 の Class Data Sharing で Spring Boot の起動を速くしてみます。
Class Data Sharing は異なるJVM上で同一のクラスの情報を共有する仕組みです。 Java 8 の時点ですでに組み込まれていましたが、コマーシャルな機能であったため、
使っている人は少ないと思います。
Java 10 からはこの機能が OpenJDK でも利用できるようになったため、早速試してみたいと思います。
Spring Boot アプリケーション
実行対象とするアプリケーションを作るために次のコマンドでプロジェクトを作ります
gradle init --type=java-library
curl https://start.spring.io/build.gradle \
-d dependencies=webflux,actuator,data-jpa,thymeleaf,\
validation,data-redis-reactive,flyway,retry,\
statemachine,mail,h2 > build.gradle
次に次のようなメインクラスを作ります。
@SpringBootApplication
public class App {
public static void main(String... args) {
SpringApplication.run(App.class, args);
}
@Bean
CommandLineRunner commandLineRunner() {
return args -> {};
}
private final Foo foo;
App(final Foo foo) {
this.foo = foo;
}
public static class Foo {}
}
JVMの起動時間だけが今は必要なので、SpringのBean読み込みが始まったらすぐに落ちるメインクラスになっています。
Spring Boot アプリケーションの起動
Spring Boot アプリケーションを起動したいのですが、 gradle の bootRun
タスクに jvm パラメーターを指定する方法でやると、 Class Data のアーカイブディレクトリーがうまく認識されなかったので、 bootJar
で作成した jar ファイルを JavaExec
タスクで起動します。
task createCdsDirectory {
outputs.dir(cdsDirectory)
doLast {
if (!cdsDirectory.exists()) {
cdsDirectory.mkdirs()
}
}
}
task runBootJar(type: JavaExec) {
main = 'org.springframework.boot.loader.JarLauncher'
dependsOn bootJar
classpath bootJar
def create = false
if (project.hasProperty('listApp')) {
jvmArgs = ['-XX:+UnlockCommercialFeatures', '-Xshare:off', "-XX:DumpLoadedClassList=${classList}", '-XX:+UseAppCDS']
create = true
} else if (project.hasProperty('dumpApp')) {
jvmArgs = ['-XX:+UnlockCommercialFeatures', '-Xshare:dump', "-XX:SharedClassListFile=${classList}", '-XX:+UseAppCDS', "-XX:SharedArchiveFile=${archiveFile}"]
create = true
} else if (project.hasProperty('runApp')) {
jvmArgs = ['-XX:+UnlockCommercialFeatures', '-Xshare:on', '-XX:+UseAppCDS', "-XX:SharedArchiveFile=${archiveFile}"]
}
if (create) {
dependsOn createCdsDirectory, showStartTime
} else {
dependsOn showStartTime
}
finalizedBy showEndTime
}
Class Data Sharing を使う場合、次の3つのフェーズがあり、それぞれで別のパラメーターを必要とします。
-XX:+UnlockCommercialFeatures
-XX:+UseAppCDS
-Xshare:off
-XX:DumpLoadedClassList=${classList}
-XX:+UnlockCommercialFeatures
-XX:+UseAppCDS
-Xshare:dump
-XX:SharedClassListFile=${classList}
-XX:SharedArchiveFile=${archiveFile}
アーカイブファイルを読みこんでアプリケーションを起動する
-XX:+UnlockCommercialFeatures
-XX:+UseAppCDS
-Xshare:on
-XX:SharedArchiveFile=${archiveFile}
ここでは、 gradle のプロパティ値の有無で起動オプションを変更する形で起動します。
また、実行時間を計測する用途として次の二つのタスクを作ります。
task showStartTime(group: 'show-time') {
doLast {
def now = LocalDateTime.now()
startTime << now
logger.lifecycle('start {}', now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME))
}
}
task showEndTime(group: 'show-time') {
doLast {
def now = LocalDateTime.now()
if (!startTime.empty) {
LocalDateTime start = startTime[0]
logger.lifecycle('start {}', start.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME))
logger.lifecycle('end {}', now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME))
def duration = Duration.between(start, now)
logger.lifecycle('time: {} ms', duration.toMillis())
}
}
}
Class Data Sharing を使わない場合
Class Data Sharing を使わない場合の起動時間を確認します。
$ ./gradlew clean runBootJar
> Task :showStartTime
start 2018-04-01T19:41:48.800745
> Task :runBootJar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.0.RELEASE)
2018-04-01 19:41:55.441 INFO 8454 --- [ main] com.example.App : Starting App on mac.local with PID 8454 (/path/to/project/build/libs/spring-app-cds-sample-0.0.1-SNAPSHOT.jar started by mike in /path/to/project)
2018-04-01 19:41:55.447 INFO 8454 --- [ main] com.example.App : No active profile set, falling back to default profiles: default
... 中略
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.App required a bean of type 'com.example.App$Foo' that could not be found.
Action:
Consider defining a bean of type 'com.example.App$Foo' in your configuration.
> Task :showEndTime
start 2018-04-01T19:41:48.800745
end 2018-04-01T19:41:59.122787
time: 10322 ms
... 以下省略
JVM起動開始 → クラスロード完了 → Spring Boot アプリケーションの起動 → Spring Boot アプリケーションの終了 の一連の流れで 10322
ms ほどかかりました。
Class Data Sharing を使う場合
クラスリストの取得
最初にアーカイブ対象のクラスをリスト化します。
$ ./gradlew runBootJar -PlistApp
> Task :showStartTime
start 2018-04-01T19:32:34.882318
> Task :runBootJar
skip writing class com/sun/proxy/$Proxy0 from source __JVM_DefineClass__ to classlist file
skip writing class com/sun/proxy/$Proxy1 from source __JVM_DefineClass__ to classlist file
skip writing class com/sun/proxy/$Proxy2 from source __JVM_DefineClass__ to classlist file
skip writing class com/sun/proxy/$Proxy3 from source __JVM_DefineClass__ to classlist file
skip writing class com/sun/proxy/$Proxy9 from source __JVM_DefineClass__ to classlist file
skip writing class com/sun/proxy/jdk/proxy1/$Proxy11 from source __JVM_DefineClass__ to classlist file
skip writing class java/lang/invoke/BoundMethodHandle$Species_LII from source __JVM_DefineClass__ to classlist file
skip writing class java/lang/invoke/BoundMethodHandle$Species_LIIL from source __JVM_DefineClass__ to classlist file
skip writing class java/lang/invoke/BoundMethodHandle$Species_LIILL from source __JVM_DefineClass__ to classlist file
skip writing class java/lang/invoke/BoundMethodHandle$Species_LIILLL from source __JVM_DefineClass__ to classlist file
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.0.RELEASE)
2018-04-01 19:32:41.717 INFO 8413 --- [ main] com.example.App : Starting App on mac.local with PID 8413 (/path/to/paroject/build/libs/spring-app-cds-sample-0.0.1-SNAPSHOT.jar started by mike in /path/to/project)
2018-04-01 19:32:41.725 INFO 8413 --- [ main] com.example.App : No active profile set, falling back to default profiles: default
skip writing class com/sun/proxy/$Proxy13 from source __JVM_DefineClass__ to classlist file
skip writing class com/sun/proxy/$Proxy24 from source __JVM_DefineClass__ to classlist file
2018-04-01 19:32:41.853 INFO 8413 --- [ main] onfigReactiveWebServerApplicationContext : Refreshing org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext@1139b2f3: startup date [Sun Apr 01 19:32:41 JST 2018]; root of context hierarchy
skip writing class java/lang/invoke/BoundMethodHandle$Species_LLLII from source __JVM_DefineClass__ to classlist file
skip writing class java/lang/invoke/BoundMethodHandle$Species_LLLIIL from source __JVM_DefineClass__ to classlist file
skip writing class java/lang/invoke/BoundMethodHandle$Species_LLLIILL from source __JVM_DefineClass__ to classlist file
skip writing class java/lang/invoke/BoundMethodHandle$Species_LLLIILLL from source __JVM_DefineClass__ to classlist file
skip writing class java/lang/invoke/BoundMethodHandle$Species_LLLIILLLL from source __JVM_DefineClass__ to classlist file
... 中略
> Task :showEndTime
start 2018-04-01T19:32:34.882318
end 2018-04-01T19:32:45.295433
time: 10413 ms
... 以下省略
これによって、次のようなテキストファイルが作成されます。(このサンプルでは build/cds/list.txt
が作成される)
$ head -10 build/cds/list.txt
java/lang/Object
java/lang/String
java/io/Serializable
java/lang/Comparable
java/lang/CharSequence
java/lang/Class
java/lang/reflect/GenericDeclaration
java/lang/reflect/AnnotatedElement
java/lang/reflect/Type
java/lang/Cloneable
$ grep spring build/cds/list.txt | head -10
org/springframework/boot/loader/JarLauncher
org/springframework/boot/loader/ExecutableArchiveLauncher
org/springframework/boot/loader/Launcher
org/springframework/boot/loader/LaunchedURLClassLoader
org/springframework/boot/loader/archive/Archive
org/springframework/boot/loader/archive/JarFileArchive
org/springframework/boot/loader/jar/JarFile
org/springframework/boot/loader/jar/CentralDirectoryVisitor
org/springframework/boot/loader/data/RandomAccessData
org/springframework/boot/loader/jar/FileHeader
もし、ロードされたくないようなクラスがある場合は、このリストから取り除きます。
リストを取得する処理が入る場合は、ロードされるクラスのスキャンニングが入るため、若干処理が遅くなります。
次にアーカイブファイルを取得します。このときの java
コマンドはアプリケーションを起動しません。
$ ./gradlew runBootJar -PdumpApp
> Task :showStartTime
start 2018-04-01T20:08:10.186895
> Task :runBootJar
narrow_klass_base = 0x0000000800000000, narrow_klass_shift = 3
Allocated temporary class space: 1073741824 bytes at 0x00000008c0000000
Allocated shared space: 3221225472 bytes at 0x0000000800000000
Loading classes to share ...
Loading classes to share: done.
Rewriting and linking classes ...
Rewriting and linking classes: done
Number of classes 2131
instance classes = 2053
obj array classes = 70
type array classes = 8
Updating ConstMethods ... done.
Removing unshareable information ... done.
Scanning all metaspace objects ...
Allocating RW objects ...
Allocating RO objects ...
Relocating embedded pointers ...
Relocating external roots ...
Dumping symbol table ...
Dumping String objects to closed archive heap region ...
Dumping objects to open archive heap region ...
Relocating SystemDictionary::_well_known_klasses[] ...
Removing java_mirror ... done.
mc space: 8536 [ 0.0% of total] out of 12288 bytes [ 69.5% used] at 0x0000000800000000
rw space: 5943264 [ 19.0% of total] out of 5943296 bytes [100.0% used] at 0x0000000800003000
ro space: 11971160 [ 38.4% of total] out of 11972608 bytes [100.0% used] at 0x00000008005ae000
md space: 6160 [ 0.0% of total] out of 8192 bytes [ 75.2% used] at 0x0000000801119000
od space: 11275744 [ 36.1% of total] out of 11276288 bytes [100.0% used] at 0x000000080111b000
st0 space: 835584 [ 2.7% of total] out of 835584 bytes [100.0% used] at 0x00000007bfe00000
st1 space: 1048576 [ 3.4% of total] out of 1048576 bytes [100.0% used] at 0x00000007bff00000
oa0 space: 102400 [ 0.3% of total] out of 102400 bytes [100.0% used] at 0x00000007bfd00000
total : 31191424 [100.0% of total] out of 31199232 bytes [100.0% used]
> Task :showEndTime
start 2018-04-01T20:08:10.186895
end 2018-04-01T20:08:11.906736
time: 1719 ms
BUILD SUCCESSFUL in 4s
6 actionable tasks: 3 executed, 3 up-to-date
これによって、アーカイブファイルが作られます(この例では build/cds/app.jsa
)。また、ログの意味を文字通りに解釈するなら、 2131
個のクラスがアーカイブされたようです。実際にファイルを確認してみます。
$ ls -l build/cds/
total 61080
-r--r--r--+ 1 mike staff 31203328 4 1 20:08 app.jsa
-rw-r--r--+ 1 mike staff 69515 4 1 19:54 list.txt
アーカイブファイルを読み込んでアプリケーションを起動する
では、作成したアーカイブファイルを使って、 Spring Boot アプリケーションを起動してみます。
$ ./gradlew runBootJar -PrunApp
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
> Task :showStartTime
start 2018-04-01T20:11:56.633207
> Task :runBootJar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.0.RELEASE)
2018-04-01 20:12:03.401 INFO 8564 --- [ main] com.example.App : Starting App on mac.local with PID 8564 (/path/to/project/build/libs/spring-app-cds-sample-0.0.1-SNAPSHOT.jar started by mike in /path/to/project)
2018-04-01 20:12:03.409 INFO 8564 --- [ main] com.example.App : No active profile set, falling back to default profiles: default
... 中略
> Task :showEndTime
start 2018-04-01T20:11:56.633207
end 2018-04-01T20:12:06.830557
time: 10197 ms
... 以下省略
全体の時間は 10197
ms となり、指定しなかったとき(10322
ms)に比べて、 125
ms ほど速くなりました!…あれ、いや、これ誤差ですよね…??!?!
問題と解決
さて、起動時間がほとんど変わらない理由を考えます。先ほどの list.txt
をよく見てみます。
org/springframework/boot/loader/JarLauncher
org/springframework/boot/loader/ExecutableArchiveLauncher
org/springframework/boot/loader/Launcher
といったクラスがアーカイブされていますが、これらを見てわかるかもしれませんが、 bootJar
によって生成される jar ファイルは一般的な fat jar とは異なり、アプリケーションのクラスがそのまま入っているのではなく、 アプリケーションの jar が中に入っています。確認してみます。
$ unzip -Z1 build/libs/spring-app-cds-sample-0.0.1-SNAPSHOT.jar
org/
org/springframework/
org/springframework/boot/
org/springframework/boot/loader/
org/springframework/boot/loader/data/
org/springframework/boot/loader/util/
org/springframework/boot/loader/archive/
org/springframework/boot/loader/jar/
org/springframework/boot/loader/data/RandomAccessDataFile.class
org/springframework/boot/loader/util/SystemPropertyUtils.class
org/springframework/boot/loader/archive/Archive$EntryFilter.class
org/springframework/boot/loader/archive/ExplodedArchive$FileEntry.class
org/springframework/boot/loader/archive/Archive.class
org/springframework/boot/loader/archive/Archive$Entry.class
org/springframework/boot/loader/Launcher.class
... 中略
BOOT-INF/classes/com/example/App$Foo.class
BOOT-INF/classes/com/example/App.class
... 中略
BOOT-INF/lib/spring-boot-starter-webflux-2.0.0.RELEASE.jar
BOOT-INF/lib/spring-boot-starter-actuator-2.0.0.RELEASE.jar
BOOT-INF/lib/spring-boot-starter-data-jpa-2.0.0.RELEASE.jar
BOOT-INF/lib/spring-boot-starter-thymeleaf-2.0.0.RELEASE.jar
BOOT-INF/lib/spring-boot-starter-validation-2.0.0.RELEASE.jar
BOOT-INF/lib/spring-boot-starter-data-redis-reactive-2.0.0.RELEASE.jar
... 以下省略
つまり、どんなにたくさん依存ライブラリーを使っても bootJar
タスクで作成した jar ファイルを Class Data Sharing で起動してもあまり効果がないことがわかります。
そこで、 bootRun
のようなラウンチャー経由で起動するわけではない形で Spring Boot アプリケーションを起動したいのですが、前述の通り bootRun
に Class Data Sharing のオプションをつけて起動すると、どうしてもアーカイブファイルのパスがうまく認識されません。正確には次のようなコマンドで bootRun
は起動されるのですが、アプリケーションのクラスがあるディレクトリーをアーカイブファイルのディレクトリーと認識してしまい、アーカイブファイルを出力してくれません。
java \
-XX:+UnlockCommercialFeatures \
-XX:+UseAppCDS \
-Xshare:dump \
-XX:SharedClassListFile=classes.txt \
-XX:SharedArchiveFile=archive.jsa \
-cp /path/to/project/build/classes/java/main:/path/to/.gradle/foo/bar/spring-foo-bar-1.0.0.jar \
com.sample.App
したがって、 bootRun
とほぼ同様のコマンドで、コンパイルされたアプリケーションをクラスファイルのままではなく、一度 jar に固めて起動するようなタスクを作る必要があります(。もちろん、普通に jar ファイルを作って、それを起動するのでも構いませんが、 jar
タスクは Spring Boot plugin によって上書きされているので、あらためて作る必要があります)。
というわけで、そのようなタスクを作り、そのタスク名を cdsBootRun
(実装、スクリプトは省略) とします。
再確認
では cdsBootRun
を使って、起動してみます。
クラスリストの取得
$ ./gradlew cdsBotRun -PlistApp
> Task :showStartTime
start 2018-04-02T23:00:45.980764
> Task :cdsBootRun
skip writing class com/sun/proxy/$Proxy0 from source __JVM_DefineClass__ to classlist file
skip writing class com/sun/proxy/$Proxy1 from source __JVM_DefineClass__ to classlist file
... 中略
Action:
Consider defining a bean of type 'com.example.App$Foo' in your configuration.
> Task :showEndTime
start 2018-04-02T23:00:45.980764
end 2018-04-02T23:00:55.548887
time: 9568 ms
クラスリストを取得するようにJVMパラメーターを調整して実行し、クラスファイルリスト list.txt
の中身を確認します。
$ grep spring build/cds/list.txt | head -10
org/springframework/boot/SpringApplication
org/springframework/boot/ApplicationArguments
org/springframework/context/ApplicationContext
org/springframework/core/env/EnvironmentCapable
org/springframework/beans/factory/ListableBeanFactory
org/springframework/beans/factory/BeanFactory
org/springframework/beans/factory/HierarchicalBeanFactory
org/springframework/context/MessageSource
org/springframework/context/ApplicationEventPublisher
org/springframework/core/io/support/ResourcePatternResolver
spring
を含むクラスの先頭10行を取得しましたが、先ほどのクラスファイルリストとは異なっていることがわかると思います。これはかなり期待できます!
アーカイブファイルを取得します。
$ ./gradlew cdsBootRun -PdumpApp
> Task :showStartTime
start 2018-04-02T23:06:08.353299
> Task :cdsBootRun
narrow_klass_base = 0x0000000800000000, narrow_klass_shift = 3
Allocated temporary class space: 1073741824 bytes at 0x00000008c0000000
Allocated shared space: 3221225472 bytes at 0x0000000800000000
Loading classes to share ...
Preload Warning: Cannot find com/sun/proxy/$Proxy4
Preload Warning: Cannot find org/springframework/core/$Proxy5
Preload Warning: Cannot find org/springframework/core/$Proxy6
Preload Warning: Cannot find com/sun/proxy/$Proxy7
Preload Warning: Cannot find com/sun/proxy/$Proxy8
... 中略
Rewriting and linking classes: done
Number of classes 6389
instance classes = 6297
obj array classes = 84
type array classes = 8
Updating ConstMethods ... done.
Removing unshareable information ... done.
Scanning all metaspace objects ...
Allocating RW objects ...
Allocating RO objects ...
Relocating embedded pointers ...
Relocating external roots ...
Dumping symbol table ...
Dumping String objects to closed archive heap region ...
Dumping objects to open archive heap region ...
Relocating SystemDictionary::_well_known_klasses[] ...
Removing java_mirror ... done.
mc space: 9544 [ 0.0% of total] out of 12288 bytes [ 77.7% used] at 0x0000000800000000
rw space: 15875096 [ 20.8% of total] out of 15876096 bytes [100.0% used] at 0x0000000800003000
ro space: 29298616 [ 38.4% of total] out of 29298688 bytes [100.0% used] at 0x0000000800f27000
md space: 6160 [ 0.0% of total] out of 8192 bytes [ 75.2% used] at 0x0000000802b18000
od space: 27230536 [ 35.7% of total] out of 27234304 bytes [100.0% used] at 0x0000000802b1a000
st0 space: 446464 [ 0.6% of total] out of 446464 bytes [100.0% used] at 0x00000007bfc00000
st1 space: 3145728 [ 4.1% of total] out of 3145728 bytes [100.0% used] at 0x00000007bfd00000
oa0 space: 221184 [ 0.3% of total] out of 221184 bytes [100.0% used] at 0x00000007bfb00000
total : 76233328 [100.0% of total] out of 76242944 bytes [100.0% used]
> Task :showEndTime
start 2018-04-02T23:06:08.353299
end 2018-04-02T23:06:28.96977
time: 20616 ms
BUILD SUCCESSFUL in 22s
5 actionable tasks: 3 executed, 2 up-to-date
さて、このコマンドの結果にも大きな変更がありました。最初に試したときは 2131
個のファイルがアーカイブされたのに対して、今度は 6389
個のファイルがアーカイブされたようです。
$ ls -l build/cds/
total 149600
-r--r--r--+ 1 mike staff 76271616 4 2 23:06 app.jsa
-rw-r--r--+ 1 mike staff 323139 4 2 23:00 list.txt
また、ファイルの大きさを確認しても、最初のときは 31,203,328
だったのに対して、 76,271,616
に増えています。これは本当に期待できそうですよ!
アーカイブファイルを読み込んでアプリケーションを起動する
ではアーカイブファイルを読み込んでアプリケーションを起動してみます。
$ ./gradlew cdsBootRun -PrunApp
> Task :showStartTime
start 2018-04-02T23:14:33.147381
> Task :cdsBootRun
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.0.RELEASE)
2018-04-02 23:14:39.305 INFO 10455 --- [ main] com.example.App : Starting App on mac.local with PID 10455 (/path/to/project/build/customJar/spring-app-cds-sample-0.0.1-SNAPSHOT.jar started by mike in /path/to/project)
2018-04-02 23:14:39.307 INFO 10455 --- [ main] com.example.App : No active profile set, falling back to default profiles: default
... 中略
> Task :showEndTime
start 2018-04-02T23:14:33.147381
end 2018-04-02T23:14:41.733068
time: 8585 ms
... 以下略
結果としては次のようになりました。
先ほどと比べて…と言いたいところですが、起動するものが変わったので最初にCDSを使わなかったものを比較対象にするのは間違っていますので、あらためてCDSを使わない場合の起動時間を調べてみます。
$ ./gradlew cdsBootRun
> Task :showStartTime
start 2018-04-02T23:22:34.634671
> Task :cdsBootRun
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.0.RELEASE)
2018-04-02 23:22:40.818 INFO 10507 --- [ main] com.example.App : Starting App on mac.local with PID 10507 (/path/to/project/build/customJar/spring-app-cds-sample-0.0.1-SNAPSHOT.jar started by mike in /path/to/project)
2018-04-02 23:22:40.822 INFO 10507 --- [ main] com.example.App : No active profile set, falling back to default profiles: default
... 中略
> Task :showEndTime
start 2018-04-02T23:22:34.634671
end 2018-04-02T23:22:43.906533
time: 9271 ms
... 以下略
CDSを使わなかった場合の起動時間は次のようになりました。
比較してみると、 CDS を使った場合の方が 686
ms ほど速くなりました!
条件 |
時間(ms) |
CDS使った場合 |
8585 |
CDS使わない場合 |
9271 |