実行エンジンは Java 仮想マシンのコア コンポーネントの 1 つであり、実行エンジンはソフトウェア自体によって実装されます。
1. 実行時のスタックフレーム構造
- Java 仮想マシンは最も基本的な実行単位としてメソッドを使用し、「スタック フレーム」は仮想マシンのメソッド呼び出しとメソッド実行をサポートするために使用されます。
- スタック フレームには、ローカル変数テーブル、オペランド スタック、ダイナミック リンク、メソッドの戻りアドレス、およびいくつかの追加情報が含まれます。
- Java ソース コードをコンパイルするときに、必要なローカル変数テーブルとオペランド スタックの深さが計算され、Code 属性に書き込まれます。
- アクティブなスレッドでは、スタックの最上位のメソッドのみが実行されます (現在のスタック フレーム)
- ローカル変数テーブル
- 変数値のセット用のストレージ スペース。メソッド パラメータとメソッド内で定義されたローカル変数を格納します。容量の最小単位として変数スロットを使用します。
- 各変数スロットは長さ 32 ビットのメモリ空間を占有する必要があります。
- プロセッサ、オペレーティング システム、または仮想マシンの実装によって異なる場合があります
- 変数スロットを 32 ビット仮想マシンと同じように見せるために、アライメントとパディングを使用する必要がある
- Java 仮想マシンは、2 つの連続する変数スロット スペース (long、double) を上位に位置合わせされた方法で割り当てます。
- オペランドスタック
- 操作スタック、後入れ先出し。コンパイル中に最大深さが Code 属性の max_stacks データ項目に書き込まれます。
- Javac コンパイラのデータ フロー分析作業により、メソッドの実行中は常に、オペランド スタックの深さが max_stacks データ項目に設定された最大値を超えないことが保証されます。
- 実行の開始時に、さまざまなバイトコード命令が内容をオペランド スタックに書き込み、抽出します。つまり、ポップとプッシュです。
- 2 つの異なるスタック フレームは、異なるメソッドの仮想マシン スタック要素として互いに独立しています。
- Java仮想マシンの解釈および実行エンジンは「スタックベースの実行エンジン」と呼ばれ、スタックはオペランドスタックです。
- ダイナミックリンク
- 各スタック フレームには、ランタイム定数プール内でスタック フレームが属するメソッドへの参照が含まれており、この参照はメソッド呼び出し中の動的接続をサポートします。
- シンボル参照の一部は、クラスのロード段階または初めて使用されるときに直接参照に変換されます (静的解析)。
- 実行のたびに直接参照に変換され、この部分は動的リンクと呼ばれます。
- メソッドの戻りアドレス
- メソッド終了メソッド
- 実行エンジンは、任意のメソッドによって返されたバイトコード命令を検出します (通常の呼び出し完了)。
- 正常終了時は呼び出し元メソッドのPCカウンタの値を戻りアドレスとして使用でき、このカウンタ値はスタックフレームに保存される可能性が高い
- メソッドの実行中に例外が発生しました (異常な呼び出しが完了しました)
- 異常終了時は例外ハンドラテーブルにより判定
- 実行エンジンは、任意のメソッドによって返されたバイトコード命令を検出します (通常の呼び出し完了)。
- 終了時に可能なアクション
- 上位メソッドのローカル変数テーブルとオペランドスタックを復元し、呼び出し元のスタックフレームのオペランドスタックに戻り値をプッシュし、メソッド呼び出し命令後の命令を指すようにPCカウンタの値を調整します。
- メソッド終了メソッド
2. メソッド呼び出し
- 分析する
- すべてのメソッド呼び出しのターゲット メソッドは、クラス ファイルの定数プール内のシンボリック参照です。
- クラス読み込みの解析フェーズ中に、一部のシンボリック参照が直接参照に変換されます。
- メソッドには、プログラムが実際に実行される前に決定可能な呼び出しバージョンがあり、このメソッドの呼び出しバージョンは実行中に変更できません。
- 割当
- 静的ディスパッチ
- 過負荷
- 動的ディスパッチ
- リライト
- 単一のディスパッチと複数のディスパッチ
- 静的ディスパッチ
- 動的型付け言語
- 主な特徴は、型チェックの主要なプロセスがコンパイル時ではなく実行時に実行されることです。
3. スタックベースのバイトコード解釈および実行エンジン
- 実行について説明する
- コード実行プロセス
- javac コンパイラは、字句解析、構文解析、抽象構文ツリーのプロセスを完了し、次に構文ツリーを走査して線形バイトコード命令ストリームを生成します。
- アクションのこの部分は Java 仮想マシンの外部で実行され、インタプリタは仮想マシンの内部にあるため、Java プログラムのコンパイルは半独立した実装になります。
- コード実行プロセス
- スタックベースの命令セットとレジスタベースの命令セット
- javac コンパイラによって出力されるバイトコード命令ストリームは、基本的にスタックベースの命令セット アーキテクチャであり、バイトコード命令ストリーム内のほとんどの命令はゼロアドレス命令であり、オペランド スタックに依存して動作します。
- スタックベースのインタープリタ実行プロセス
4. OSGI: 柔軟なクラスローダーアーキテクチャ
- Java言語に基づく動的モジュール化仕様
- OSGIでは、バンドル間の依存関係が従来の上位モジュールの下位モジュールへの依存関係からフラットレベルモジュール間の依存関係に変わり、クラスライブラリの可視性が非常に精密に制御されています。
- モジュールのエクスポートされたパッケージのみが外部からアクセスでき、他のパッケージとクラスは非表示になります。
- OSGI のバンドル クラス ローダー間にはルールのみがあり、固定された委任関係はありません。
- Bundle クラス ローダーが他の Bundle にサービスを提供する場合、Export-Package リストに従ってアクセス範囲を厳密に制御します。
- エクスポートがない場合、他のバンドルに提供されず、他のバンドルのクラス ロード リクエストがこのバンドルに割り当てられて処理されることもありません。