Java仮想マシンにおけるプログラム実行の仕組み

Java仮想マシンにおけるプログラム実行の仕組み

以下に示す簡単なJavaメソッドを用いて、JVMでの実行プロセスを詳細に説明します。

public int calculateSum(int x, int y) {
    return x + y;
}

1. Javaコードの作成とコンパイル

JavaソースコードをCalculator.javaとして保存し、javacコンパイラでバイトコードに変換します:

javac Calculator.java

この処理によりCalculator.classファイルが生成され、Javaバイトコードが含まれます。

2. JVMへのバイトコード読み込み

以下のコマンドでプログラムを実行すると:

java Calculator

JVMが起動し、バイトコードの実行が開始されます。

3. クラスローダーの役割

JVMのクラスローダーがCalculator.classファイルを読み込み、クラス定義をメモリに展開します。これにはメソッドのバイトコードも含まれます。

4. メソッドエリア

読み込まれたクラスとメソッドのバイトコードはJVMのメソッドエリアに格納されます。calculateSumメソッドのバイトコードは以下のようになります:

public int calculateSum(int x, int y);
  Code:
   0: iload_1
   1: iload_2
   2: iadd
   3: ireturn

5. 実行エンジンの動作

インタプリタ実行

JVMの実行エンジンがバイトコードを逐次解釈・実行します:

  • プログラムカウンタ:各スレッドが独立して保持し、現在実行中のバイトコード命令を指します
  • オペランドスタック:演算対象と中間結果を保持します
  • ローカル変数テーブル:メソッドパラメータとローカル変数を格納します

calculateSum(4, 5)の呼び出し例では:

バイトコード命令の実行フロー
  1. 命令 0: iload_1 - 第一引数x(値4)をオペランドスタックに積む - オペランドスタック:[4]
  2. 命令 1: iload_2 - 第二引数y(値5)をオペランドスタックに積む - オペランドスタック:[4, 5]
  3. 命令 2: iadd - オペランドスタックから2つの値4と5を取り出し、加算実行後、結果9をスタックに戻す - オペランドスタック:[9]
  4. 命令 3: ireturn - オペランドスタックから値9を取り出し、メソッド戻り値として返す
ローカル変数テーブルの状態

calculateSumメソッド呼び出し時のローカル変数テーブル:

  • ローカル変数テーブル:[this, 4, 5] - this:現在のオブジェクト参照(インスタンスメソッドの場合) - 4:パラメータxの値 - 5:パラメータyの値

6. 実行エンジンの詳細動作

プログラムカウンタの推移

バイトコード命令実行時のプログラムカウンタの変化:

  • 初期状態:PC = 0
  • iload_1実行後:PC = 1
  • iload_2実行後:PC = 2
  • iadd実行後:PC = 3
  • ireturn実行後:メソッド終了、呼び出し元に戻る

7. JITコンパイラの最適化

calculateSumメソッドが頻繁に呼び出される場合、JVMのJITコンパイラはバイトコードをネイティブマシンコードに変換し、実行効率を向上させます。コンパイル後のマシンコードはCPUが直接実行するため、インタプリタによる逐次解釈が不要になります。

8. 呼び出し元への戻り

メソッド戻り値9が呼び出し元に渡され、後続のコード実行が継続されます。

実行プロセスの全体図

Javaコード -> コンパイラ(javac) -> バイトコード(Calculator.class) -> JVM
 -> クラスローダー -> メソッドエリア -> 実行エンジン
  -> [プログラムカウンタ, オペランドスタック, ローカル変数テーブル]
   -> バイトコード逐次実行(インタプリタ)
    -> JITコンパイル(オプション)
     -> ネイティブマシンコード実行(性能向上)

主要コンポーネントのまとめ

  • クラスローダー:バイトコードをメモリに読み込み
  • メソッドエリア:クラスとメソッドバイトコードを格納
  • 実行エンジン:バイトコードの解釈実行またはネイティブコードへのコンパイル
  • プログラムカウンタ:現在実行中のバイトコード命令を指示
  • オペランドスタック:演算対象と中間結果を保持
  • ローカル変数テーブル:メソッドパラメータとローカル変数を管理

以上の説明により、JVM内部での命令実行フローの全体像と、CPU、実行エンジン、プログラムカウンタ、オペランドスタック、マシン命令間の関係性が明確になりました。

タグ: JVM Javaバイトコード クラスローダー 実行エンジン JITコンパイラ

5月14日 20:51 投稿