Dev Study
← Spring コース

13. JVM は何を読んで実行するのか

が読むのは というファイルです。1つにつき1ファイルで、中身は が先に作っておいた(JVM 向けの命令列)です。OS が起動するのは コマンドだけで、.class も も実行ファイルではなく、java が開いて読む入力です。手元の Linux で、開かれたファイルを順に記録したものが図です。

読む場所は名前から組み立てます。(探す起点。ここでは out)に、クラス名 com.example.demo.Hello の点をスラッシュに替えたものと .class を足して、out/com/example/demo/Hello.class です。2つ目の Helper.class は起動時ではなく、 が Helper を初めて使う行で開かれました。JAR から読む場合も、必要になった時点で中の項目を読みます。

Node が読むのは main.js というテキストで、 が実行時に中でバイトコードへ変換します。Java はその変換をビルド時に javac で済ませている、という違いです。なお、使う時点で読むのはこの JVM の動きで、仕様がそう決めているわけではありません。Node も require はその行で読みますが、ES の は実行前に両方読まれました。

点線の付いた語はタップすると説明が出ます。用語集を開く →

java -cp out com.example.demo.Hello で開かれたファイルの順(strace の記録)
javaOS が起動するのはこの実行ファイルだけ
Node: node
java が JDK の中のファイルを開く
libjvm.soJVM 本体
lib/modulesJDK 標準クラスの入れ物
classes.jsa標準クラスの共有アーカイブ
クラスパス out + 名前から組み立てたパス
out/com/example/demo/Hello.class1000 バイトを読む。先頭は CAFEBABE
Node: main.js(テキスト)
main が動き出す
出力: step 1: main startedこの時点で Helper.class はまだ開かれていない
Helper を初めて使う行に来る
out/com/example/demo/Helper.classここで初めて開いて 710 バイトを読む
Node: require('./helper.js') の行で helper.js
出力: step 2: hello, JVM
  • ・Temurin 25.0.4.1 を Linux(aarch64)のコンテナで動かし、strace で記録しました。3回とも同じ順でした。共有ライブラリなど一部のファイルは図から省いています
  • ・String など JDK の標準クラスは、.class を1個ずつ開いているのではありません。lib/modules と classes.jsa をそれぞれ1回開くだけでした。この2つのファイル名と形式はこの JVM(HotSpot)の実装のものです
  • ・java -jar app.jar の場合、JAR は2回開かれました。1回目は java コマンドがマニフェスト(JAR の中の設定ファイル。入口のクラス名が書いてある)を読んですぐ閉じます。2回目は JVM が動き出してから開かれ、以後は開いたままで、必要になった項目の位置へ移動して読みます。クラスごとに開き直してはいません
  • ・JVM の仕様(JVMS SE 25 §5.4)は、クラスの中にある他のクラスへの参照の解決について、使う時点で1つずつ行う実装と、検証のときにまとめて行う実装の両方を認めています
  • ・V8 の公式ブログによると、V8 は JavaScript をまず Ignition というインタプリタ用のバイトコードにし、その先に Sparkplug、Maglev、TurboFan という機械語を作る段があります(記事は 2016〜2023 年のもの)。Node は v24.21.0 で確かめました

▶ サンプルコードを実行してみよう(自由に書き換えてOK)

Java

図やコードに出てくる用語(タップで説明)

サンプルコードで身につける(5本) →

学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。

公式ドキュメントで詳しく ↗