サンプルコードで身につける: JVM の起動とクラスロード、JIT
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1クラスを読み込んだのは誰か
を読み込む係をと呼びます。String のような は 内蔵のローダが読むため、getClassLoader() は null を返します。自分で書いた Main は、アプリケーション用のローダ(AppClassLoader)が読み込んでいます。
2クラスロードのログ
読み込まれたクラスを1行ずつ出すオプションを付けて Hello を実行したものです。全 609 行のうち、自分の Hello は 401 行目に file:/w/ から読み込まれています。それ以外の行のほとんどは shared objects file()が出どころです。
[0.006s][info][class,load] java.lang.Object source: shared objects file[0.007s][info][class,load] java.io.Serializable source: shared objects file[0.007s][info][class,load] java.lang.Comparable source: shared objects file[0.007s][info][class,load] java.lang.CharSequence source: shared objects file...[0.020s][info][class,load] java.security.Permissions source: shared objects file[0.020s][info][class,load] Hello source: file:/w/[0.020s][info][class,load] java.lang.NamedPackage source: shared objects file...[0.026s][info][class,load] java.lang.Shutdown source: shared objects file[0.026s][info][class,load] java.lang.Shutdown$Lock source: shared objects file
3共有アーカイブがあるときと無いとき
既定では のクラスの大半を、あらかじめ用意された共有アーカイブ(CDS)から取り込んでいました。 で切ると 620 個を jrt:/java.base から読み込むようになり、起動は各巡の1回目を除いて 14〜17 ミリ秒から 30〜34 ミリ秒に伸びました。行数は JDK の版でも変わります。
条件 行数 共有アーカイブ jrt:/java.baseJDK 25 既定 609 605 2JDK 25 -Xshare:off 622 0 620JDK 22 既定 531 522 2
4JIT があるときと無いとき
同じを 2000 ラウンド呼び、1ラウンドの時間をマイクロ秒で出した実測です。既定では1ラウンド目が 1176 で4ラウンド目以降は 70 前後に落ち着き、(だけ)では最後まで約 600 のままでした。3ラウンド目が跳ねた理由は特定できておらず、数値はこの計算とこの機械でのものです。
## default run 1round us: [1]=1176 [2]=223 [3]=1126 [4]=70 [5]=70 [6]=70 [7]=70 [8]=70 [9]=70 [10]=70 [20]=70 [50]=70 [100]=70 [200]=70 [500]=77 [1000]=69 [2000]=69rounds 1001-2000 (us): min=69 median=69 max=109## -Xint run 1round us: [1]=674 [2]=637 [3]=620 [4]=615 [5]=597 [6]=590 [7]=590 [8]=611 [9]=597 [10]=573 [20]=597 [50]=598 [100]=600 [200]=600 [500]=611 [1000]=598 [2000]=610rounds 1001-2000 (us): min=539 median=609 max=844
5Hello の起動時間を Node・Rust と並べる
プロセスを起こしてから終わるまでを10回ずつ2巡測った値です。各巡の1回目を除くと が 14〜17、node が 10〜12、Rust が 0.7〜2.0 ミリ秒(外れ値 6.3 が1回)で、何もしない /bin/true でも 0.4〜1.1(外れ値 3.7 が1回)かかるため、Rust の値はプロセスを起こす費用とほぼ区別できません。別々ので測っており、言えるのは順序と桁までです。
java Hello(JDK 25 既定)1巡目: 21.5 15.6 16.8 15.9 16.0 16.2 15.0 15.4 17.2 17.42巡目: 18.0 15.7 13.9 15.3 14.5 15.9 15.7 16.0 14.9 14.6node hello.js(v24.21.0)1巡目: 15.0 12.3 11.3 11.5 10.8 11.0 11.2 11.1 10.7 10.92巡目: 17.0 11.8 10.6 9.9 9.6 10.6 11.8 10.8 11.8 10.8Rust の実行ファイル1巡目: 2.3 1.8 1.2 1.0 1.0 1.0 0.8 0.8 0.7 0.82巡目: 1.7 2.0 6.3 1.6 1.1 1.1 1.2 1.0 0.9 0.8/bin/true(計測の下限)1巡目: 1.8 1.1 0.6 0.8 3.7 0.5 0.4 0.5 0.5 0.42巡目: 0.5 1.0 1.0 0.7 0.8 0.6 0.5 0.4 0.4 0.4