JVM 仕様は抽象的な実行モデルを定義するものであり、オペレーティングシステムのメモリマップを定義するものではありません。実装は、仕様で定められた動作を維持しながら、JIT コンパイル、移動ガベージコレクション、連続または分割されたストレージ、ネイティブメタデータを使用できます。
実行時データ領域 #
各 JVM スレッドには、プログラムカウンターレジスター、JVM スタック、そして任意でネイティブメソッドスタックがあります。PC は Java コードの現在の JVM 命令を識別し、ネイティブコード実行中は未定義の値になります。JVM スタックはフレームを保持します。フレームを作成できない場合、サイズ上限では StackOverflowError が、拡張可能なスタックを拡大できない場合は OutOfMemoryError が発生します。
ヒープは共有され、オブジェクトと配列を含みます。メソッド領域は共有され、クラスごとの構造を保持します。HotSpot のメタスペースなどの具体的な配置は実装に依存します。すべてのクラスまたはインターフェイスにはランタイム定数プールがあり、クラスファイルの定数とシンボリック参照の実行時形式を保持します。これらの共有領域にはクラスロードを通じて到達し、スレッドのフレームとは分離されています。
フレームと実行 #
各メソッド呼び出しは、ローカル変数配列、オペランドスタック、現在のクラスのランタイム定数プールへの参照、戻りまたは例外完了の状態を持つフレームを作成します。クラスファイルの max_locals と max_stack は最初の 2 つの領域の上限です。バイトコードはローカル変数とオペランドスタックの間で値を移動し、呼び出し命令はシンボリック参照を解決して新しいフレームに制御を移します。正常終了では結果が呼び出し元のオペランドスタックに返され、異常終了では VM が巻き戻しながら例外ハンドラーを検索します。
クラスローダーはクラスファイルのバイト列を提供し、型の同一性を確立します。実行エンジンはバイトコードを検証、解釈し、コンパイルすることがありますが、クラスローダーではありません。JVMS は、エンジンのアーキテクチャを規定するのではなく、ロード、リンク、初期化、命令実行の観点から両者の境界を定義します。
ブール値と終了 #
JVM には専用のブール算術命令がありません。Java コンパイラーはブール式に int の計算値を使用し、boolean 配列には baload と bastore でアクセスします。仕様では、格納されるエンコーディングに false は 0、true は 1 を使用することが要求されます。バイトコードの慣例から Java オブジェクトのフィールドレイアウトを推測しないでください。
Java アプリケーションは通常、最後の非デーモンスレッドが終了すると終了します。System.exit はランタイムを通じて VM の終了を要求しますが、1 つのスレッドの回復不能な失敗によって他の非デーモンスレッドが終了することはありません。ネイティブコード、シャットダウンフック、ホストプロセスは、観測されるシャットダウン動作に影響します。
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)