概要
HotSpot Runtime Overviewにはこう書いています
The VM loads core classes such as
java.lang.Object
,java.lang.Thread
, etc. at JVM startup. Loading a class requires loading all superclasses and superinterfaces. And classfile verification, which is part of the linking phase, can require loading additional classes.
- JVMは起動したすぐ
java.lang.Object
、java.lang.Thread
などの Class をロードする - 依頼された super と interface は自動にロードする
- その他の Class は必要なときだけにロードする
じゃ具体的にはどんな Class をいつにロードされたのか?Unified JVM Logging を利用して実際に見に行きましょう。
作業環境
前の記事との同じく Ubuntu 18.04 と OpenJDK 13 を使いています、具体的の構築方法はそちらに参照してください。
startuptime
を見てみる
まずは-Xlog:startuptime
の変数でJVMの大まかの起動時間が見てみよう
$ $JAVA_HOME/bin/java -Xlog:startuptime -version
[0.168s][info][startuptime] StubRoutines generation 1, 0.0257810 secs
[0.229s][info][startuptime] Genesis, 0.0605841 secs
[0.232s][info][startuptime] TemplateTable initialization, 0.0010887 secs
[0.263s][info][startuptime] Interpreter generation, 0.0302811 secs
[0.693s][info][startuptime] StubRoutines generation 2, 0.0152926 secs
[0.697s][info][startuptime] MethodHandles adapters generation, 0.0017809 secs
[0.703s][info][startuptime] Start VMThread, 0.0010136 secs
[0.997s][info][startuptime] Initialize java.lang classes, 0.2923160 secs
[1.018s][info][startuptime] Initialize java.lang.invoke classes, 0.0159241 secs
[3.161s][info][startuptime] Initialize module system, 2.1431533 secs
[3.173s][info][startuptime] Create VM, 3.1052374 secs
openjdk version "13.0.3-internal" 2020-04-14
OpenJDK Runtime Environment (fastdebug build 13.0.3-internal+0-adhoc.root.jdk13u)
OpenJDK 64-Bit Server VM (fastdebug build 13.0.3-internal+0-adhoc.root.jdk13u, mixed mode)
ここでわかるのはStart VMThread
のあどで幾つの classe と modules を初期化しました。
[0.997s][info][startuptime] Initialize java.lang classes, 0.2923160 secs
[1.018s][info][startuptime] Initialize java.lang.invoke classes, 0.0159241 secs
[3.161s][info][startuptime] Initialize module system, 2.1431533 secs
Class のload
とinit
を見る
次は-Xlog:startuptime,class+init,class+load
の変数を設定してもう一度実行しましょう。
$ $JAVA_HOME/bin/java -Xlog:startuptime,class+init,class+load -version
[0.096s][info][class,load] path: /vagrant/jdk/jdk13u/build/linux-x86_64-server-fastdebug/jdk/modules/java.base
[0.159s][info][startuptime] StubRoutines generation 1, 0.0283598 secs
[0.220s][info][startuptime] Genesis, 0.0597463 secs
[0.223s][info][startuptime] TemplateTable initialization, 0.0012748 secs
[0.252s][info][startuptime] Interpreter generation, 0.0291667 secs
[0.284s][info][class,load ] path: /vagrant/jdk/jdk13u/build/linux-x86_64-server-fastdebug/jdk/modules/java.base
[0.285s][info][class,load ] path: /vagrant/jdk/jdk13u/build/linux-x86_64-server-fastdebug/jdk/modules/java.base
[0.314s][info][class,load ] java.lang.Object source: /vagrant/jdk/jdk13u/build/linux-x86_64-server-fastdebug/jdk/modules/java.base
[0.321s][info][class,load ] java.io.Serializable source: /vagrant/jdk/jdk13u/build/linux-x86_64-server-fastdebug/jdk/modules/java.base
...
[0.553s][info][class,load ] java.util.Iterator source: /vagrant/jdk/jdk13u/build/linux-x86_64-server-fastdebug/jdk/modules/java.base
[0.578s][info][class,load ] java.lang.NullPointerException source: /vagrant/jdk/jdk13u/build/linux-x86_64-server-fastdebug/jdk/modules/java.base
[0.579s][info][class,load ] java.lang.ArithmeticException source: /vagrant/jdk/jdk13u/build/linux-x86_64-server-fastdebug/jdk/modules/java.base
[0.619s][info][startuptime] StubRoutines generation 2, 0.0132195 secs
[0.622s][info][startuptime] MethodHandles adapters generation, 0.0018546 secs
[0.627s][info][startuptime] Start VMThread, 0.0007446 secs
[0.629s][info][class,init ] 0 Initializing 'java/lang/Object' (0x0000000100001080)
[0.644s][info][class,init ] 1 Initializing 'java/lang/CharSequence'(no method) (0x00000001000016b8)
...
[0.898s][info][class,init ] 135 Initializing 'java/lang/IllegalArgumentException'(no method) (0x000000010002b0e8)
[0.898s][info][startuptime] Initialize java.lang classes, 0.2690178 secs
[0.902s][info][class,init ] 136 Initializing 'java/lang/invoke/MethodHandle' (0x000000010000c560)
...
[0.925s][info][class,init ] 144 Initializing 'java/lang/invoke/MethodHandleNatives' (0x000000010000d2e8)
[0.925s][info][startuptime] Initialize java.lang.invoke classes, 0.0232579 secs
[0.935s][info][class,load ] jdk.internal.module.ModuleBootstrap source: /vagrant/jdk/jdk13u/build/linux-x86_64-server-fastdebug/jdk/modules/java.base
...
[3.112s][info][class,load ] jdk.internal.module.ModuleBootstrap$SafeModuleFinder source: /vagrant/jdk/jdk13u/build/linux-x86_64-server-fastdebug/jdk/modules/java.base
[3.113s][info][class,init ] 662 Initializing 'jdk/internal/module/ModuleBootstrap$SafeModuleFinder'(no method) (0x000000010008e930)
[3.113s][info][startuptime] Initialize module system, 2.1876125 secs
[3.124s][info][startuptime] Create VM, 3.0688743 secs
openjdk version "13.0.3-internal" 2020-04-14
OpenJDK Runtime Environment (fastdebug build 13.0.3-internal+0-adhoc.root.jdk13u)
OpenJDK 64-Bit Server VM (fastdebug build 13.0.3-internal+0-adhoc.root.jdk13u, mixed mode)
ここでわかったのは、実際には2つの段階があります
-
Interpreter generation
とStubRoutines generation 2
の間に幾つの Class がロードされました。 -
Start VMThread
あどに 663 個(0-662)の Class が初期化されました-
java.lang
136 個 (0-135) -
java.lang.invoke
9 個 (136-144) -
module system
518 個 (145-622)
-
ソースコードで確認する
上記のテキストをソースコードに検索したら、この2つの段階を触発する場所がわかります。
-
SystemDictionary::resolve_well_known_classes
:SystemDictionary
はほぼJVMの Class 管理機能がしています。このSystemDictionary
が初期化したときにいわゆる Well Know Classes というコアな Class たちも一緒に初期化する。Well Known Classes のリストはここに記載してます、その順序は大事のようです。 -
Threads::create_vm
:Start VMThread
のあどにjava.lang classes
、java.lang.invoke classes
とmodule system
を一気に初期化するのはここです。具体的にはこれらの3つの関数で
まとめ
JVMが起動したときにこれらのコアな Class を初期化します
- Well Know Classes (
SystemDictionary
の初期化とともに) -
java.lang
Class -
java.lang.invoke
Class -
$JAVA_HOME/modules
の Class