Java仮想マシン(JVM)を読解しながら理解する #02
前回記事
※上記記事の続きとして記載しています。
今回は第二章からです!!
Chapter 2. The Structure of the Java Virtual Machine(Java仮想マシンの構造)
ここに概要が記載されていると思うのですが・・・
Java仮想マシンを正しく実装するには、ファイル形式を読み取りclass、そこに指定された操作を正しく実行できれば十分です。 って書いてありました。。。。
気になっていた、ガベージコレクションアルゴリズムについては
実装者の裁量に委ねられています。 とのこと・・・
どうやら、「どの方式でGCを行うかは自由」という意味でガベージコレクションにも種類がありそうですね・・・!! そこはまた追っていけらたらと思います!!
2.1. The class File Format(classファイル形式
)
この項目では、ざっくりしたclassファイル形式についての概要についての記載で詳しくは第4章で説明とのことです。
この項目での内容は
Javaのclassファイルは、特定のOSやハードウェアに依存せず、JVMで動かすための中立的で汎用的なバイナリ形式である
そして、そのclassファイルは
クラスやインターフェースの表現(名前、継承、フィールド、メソッド、属性)を正確に定義している
とのことでした。
2.2. Data Types(データ型)
- JVMもJavaと同じく「プリミティブ型」と「参照型」で動いている
- 型チェックはほとんどコンパイル時に完了しているため、実行時にはタグ付けや動的型チェックは不要
- JVMの命令は型ごとに専用命令がある(iadd, ladd, fadd, dadd)ので、実行時に型を見て処理を切り替える必要がない
- 参照型(reference)は「オブジェクトへのポインタ」
- すべてのオブジェクト(配列含む)は 参照型の値を通じて操作される
が記載されていました。
まず、初見の単語は・・・専用命令でした!!
JVMは「型に応じて異なる命令を使う」ことによって高速で処理できるようになっているようです。
詳細は表にすると以下のような命令があるとのことです。
加算命令一覧(JVMの型別バイトコード)
| 命令 | 対応する型 | 説明 |
|---|---|---|
iadd |
int |
int型(32bit整数)の加算(integer) |
ladd |
long |
long型(64bit整数)の加算 |
fadd |
float |
float型(単精度浮動小数点)の加算 |
dadd |
double |
double型(倍精度浮動小数点)の加算 |
Javaの仕様と同じと思いますが、一応読解します。。。。
参照型(reference)は「オブジェクトへのポインタ」
です。
誤認識がないように、そもそも参照型とは??から開始します。
参照型とは、
「ヒープ上のオブジェクトを指し示すアドレスのような値」
です。
以下のサンプルコードで確認したらイメージがつきやすいと思います!!
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false → 参照が違う
System.out.println(a.equals(b)); // true → 文字列の内容が同じ
"=="では変数の中にあるそのもののを比較するため、異なったインスタンス(ヒープ領域で保管されているパスが異なる)のため違う左辺と右辺が異なった値ですと比較されるためfalseになります。
そして、ポインタとは??
「メモリ上のアドレスを直接操作するための変数」
であり、Javaでは禁止されていて近いしい概念として
- 参照型(reference)は「オブジェクトへのポインタ」
があり、以下のコードだと先ほどの実装とは異なり"=="でもtrueになります。
これがポインタっぽい参照型です!!
String a = new String("hello");
String b = a;
System.out.println(a == b); // true → 同じインスタンスを参照
System.out.println(a.equals(b)); // true → 文字列の内容が同じ
少しイメージつきましたでしょうか??
まとめると・・・・
参照型は、プリミティブ型(int, boolean, doubleなど)とは異なり、“実体そのもの”ではなく、その実体へのアクセス手段を変数として保持する
です!!
なので・・・
JVMは、
プリミティブ型は変数の実体(値そのもの)がローカル変数としてスタックフレーム上に格納し直接操作
それ以外のオブジェクトや配列は、スタックにある参照値を通してアクセス・操作する
| 種別 | スタックに格納されるもの | ヒープに格納されるもの | 操作方法 |
|---|---|---|---|
プリミティブ型 (int, boolean など) |
値そのもの(実体) | なし | スタック上で直接演算(例:iadd, iload) |
| 参照型(オブジェクト、配列など) | 参照値(ヒープへのポインタ) | オブジェクト本体 | 参照値を通じてヒープ上の実体を操作 |
次の項目はプリミティブ型と値なのですが、各プリミティブ型の話になるため長そうなので次回にまわします!!
まとめ
- JVMは抽象マシンであり、実装者は内部構造ガベージコレクションや最適化を自由に工夫できる。
- ClassファイルはOS/CPU非依存のバイナリ形式で、クラス/インターフェースの構造(名前, 継承, メンバー, 属性など)を正確に表現する。
- JVMの型は プリミティブ / 参照 の2系統ある。
- 型チェックはほぼコンパイル時に実施される想定で、JVMは実行時に型タグを見分ける必要がない。
- 命令は型付き(iadd, ladd, fadd, dadd など)**のため、実行時分岐不要で効率的。
- 参照値はオブジェクトへのポインタ的概念、クラスインスタンスも配列もオブジェクトであり、すべて参照型経由で操作される。
得た知見
- ガベージコレクションは「必ずこう実装せよ」と仕様はなく、どうやってそれを実現するかは実装者に委ねられている。
- 型安全はコンパイル時に前倒しされ、JVM命令は型ごとに分かれている=高速化と安全性の鍵。
- JVMは、Javaの構文・型システム・実行モデルを効率的に処理できるよう設計された実行環境である。
Discussion