Java仮想マシン

Java仮想マシン（ジャバかそうマシン、、、JVM）は、Javaバイトコードとして定義された命令セットを実行するスタック型の仮想マシン。APIやいくつかのツールとセットでJava実行環境（JRE）としてリリースされている。この環境を移植することで、さまざまな環境でJavaのプログラムを実行することができる。

 命令セット仕様 
 ニーモニック表 

（12、C6 などの数値は16進法表記）

    -0  -1  -2  -3  -4  -5  -6  -7  -8  -9  -A  -B  -C  -D  -E  -F 0- 00nop 01aconst_null 02iconst_m1 03iconst_0 04iconst_1 05iconst_2 06iconst_3 07iconst_4 08iconst_5 09lconst_0 0Alconst_1 0Bfconst_0 0Cfconst_1 0Dfconst_2 0Edconst_0 0Fdconst_1 1- 10bipush 11sipush 12ldc 13ldc_w 14ldc2_w 15iload 16lload 17fload 18dload 19aload 1Aiload_0 1Biload_1 1Ciload_2 1Diload_3 1Elload_0 1Flload_1 2- 20lload_2 21lload_3 22fload_0 23fload_1 24fload_2 25fload_3 26dload_0 27dload_1 28dload_2 29dload_3 2Aaload_0 2Baload_1 2Caload_2 2Daload_3 2Eiaload 2Flaload 3- 30faload 31daload 32aaload 33baload 34caload 35saload 36istore 37lstore 38fstore 39dstore 3Aastore 3Bistore_0 3Cistore_1 3Distore_2 3Eistore_3 3Flstore_0 4- 40lstore_1 41lstore_2 42lstore_3 43fstore_0 44fstore_1 45fstore_2 46fstore_3 47dstore_0 48dstore_1 49dstore_2 4Adstore_3 4Bastore_0 4Castore_1 4Dastore_2 4Eastore_3 4Fiastore 5- 50lastore 51fastore 52dastore 53aastore 54bastore 55castore 56sastore 57pop 58pop2 59dup 5Adup_x1 5Bdup_x2 5Cdup2 5Ddup2_x1 5Edup2_x2 5Fswap 6- 60iadd 61ladd 62fadd 63dadd 64isub 65lsub 66fsub 67dsub 68imul 69lmul 6Afmul 6Bdmul 6Cidiv 6Dldiv 6Efdiv 6Fddiv 7- 70irem 71lrem 72frem 73drem 74ineg 75lneg 76fneg 77dneg 78ishl 79lshl 7Aishr 7Blshr 7Ciushr 7Dlushr 7Eiand 7Fland 8- 80ior 81lor 82ixor 83lxor 84iinc 85i2l 86i2f 87i2d 88l2i 89l2f 8Al2d 8Bf2i 8Cf2l 8Df2d 8Ed2i 8Fd2l 9- 90d2f 91i2b 92i2c 93i2s 94lcmp 95fcmpl 96fcmpg 97dcmpl 98dcmpg 99ifeq 9Aifne 9Biflt 9Cifge 9Difgt 9Eifle 9Fif_icmpeq A- A0if_icmpne A1if_icmplt A2if_icmpge A3if_icmpgt A4if_icmple A5if_acmpeq A6if_acmpne A7goto A8jsr A9ret AAtableswitch ABlookupswitch ACireturn ADlreturn AEfreturn AFdreturn B- B0areturn B1return B2getstatic B3putstatic B4getfield B5putfield B6invokevirtual B7invokespecial B8invokestatic B9invokeinterface BAinvokedynamic BBnew BCnewarray BDanewarray BEarraylength BFathrow C- C0checkcast C1instanceof C2monitorenter C3monitorexit C4wide C5multianewarray C6ifnull C7ifnonnull C8goto_w C9jsr_w CAbreakpoint CB未定義 CC未定義 CD未定義 CE未定義 CF未定義 D- D0未定義 D1未定義 D2未定義 D3未定義 D4未定義 D5未定義 D6未定義 D7未定義 D8未定義 D9未定義 DA未定義 DB未定義 DC未定義 DD未定義 DE未定義 DF未定義 E- E0未定義 E1未定義 E2未定義 E3未定義 E4未定義 E5未定義 E6未定義 E7未定義 E8未定義 E9未定義 EA未定義 EB未定義 EC未定義 ED未定義 EE未定義 EF未定義 F- F0未定義 F1未定義 F2未定義 F3未定義 F4未定義 F5未定義 F6未定義 F7未定義 F8未定義 F9未定義 FA未定義 FB未定義 FC未定義 FD未定義 FEimpdep1 FFimpdep2

 オペコード解説 

 スタック 
 bipush、 sipush - byte値、 short値をスタックに積む。
 ldc - コンスタントプール内の4バイトの定数(int値、float値、java.lang.String)の内1バイト以内でエントリ番号を指定できるものをスタックに積む。
 ldc_w - エントリ番号が1バイトでは足りないときに使う。
 ldc2_w - コンスタントプール内の8バイトの定数(long値、double値)をスタックに積む。
 iconst_m1、 iconst_0、 iconst_1、 iconst_2、 iconst_3、 iconst_4、 iconst_5 - intの-1、0、1、2、3、4、5をスタックに積む。
 lconst_0、 lconst_1 - longの0、1をスタックに積む
 fconst_0、 fconst_1、 fconst_2 - floatの0、1、2をスタックに積む
 dconst_0、 dconst_1 - doubleの0、1をスタックに積む。
 aconst_null - スタックにnullを積む。
 pop、 pop2 - スタックから1、2ワード取り除く
 dup、 dup2
 dup_x1、 dup2_x1
 dup_x2、 dup2_x2
 swap

 局所変数 
 iload、 lload、 fload、 dload、 aload - 局所変数からint値、 long値、 float値、 double値、 参照値を取り出してスタックに積む。
 iload_0、 iload_1、 iload_2、 iload_3 - 0、1、2、3番目の局所変数からint値を取り出してスタックに積む。
 lload_0、 lload_1、 lload_2、 lload_3 - 0、1、2、3番目の局所変数からlong値を取り出してスタックに積む。
 fload_0、 fload_1、 fload_2、 fload_3 - 0、1、2、3番目の局所変数からfloat値を取り出してスタックに積む。
 dload_0、 dload_1、 dload_2、 dload_3 - 0、1、2、3番目の局所変数からdouble値を取り出してスタックに積む。
 aload_0、 aload_1、 aload_2、 aload_3 - 0、1、2、3番目の局所変数から参照値を取り出してスタックに積む。
 istore、 lstore、 fstore、 dstore、 astore - int値、 long値、 float値、 double値、 参照値を局所変数に格納。
 istore_0、 istore_1、 istore_2、 istore_3 - int値を0、1、2、3番目の局所変数に格納する。
 lstore_0、 lstore_1、 lstore_2、 lstore_3 - long値を0、1、2、3番目の局所変数に格納する。
 fstore_0、 fstore_1、 fstore_2、 fstore_3 - float値を0、1、2、3番目の局所変数に格納する。
 dstore_0、 dstore_1、 dstore_2、 dstore_3 - double値を0、1、2、3番目の局所変数に格納する。
 astore_0、 astore_1、 astore_2、 astore_3 - 参照値を0、1、2、3番目の局所変数に格納する。

 条件付きジャンプ 
 ifeq、 ifnull、 iflt、 ifle、 ifne、 ifnonnull、 ifgt、 ifge - スタックの値が0、 null、 0未満、 0以下、 0以外、 null以外、 0より大きい、 0以上の場合に指定の番地に制御を移す。
 if_icmpeq、 if_icmpne、 if_icmplt、 if_icmpgt、 if_icmple、 if_icmpge - 2つのint値が等しい、等しくない、＜、＞、≦、≧の場合に指定の番地に制御を移す。
 if_acmpeq、 if_acmpne - 2つの参照値が等しい、等しくない場合に指定の番地に制御を移す。

 ジャンプ 
 goto、 goto_w - それぞれ2バイト形式（符号付き16ビット）、4バイト形式（符号付き32ビット）でもつ相対番地をこの命令の番地に加えた番地に制御を移す（JavaにGO TO命令はなくても、このようにJava仮想マシンにgoto命令はある）。
 jsr、 jsr_w - サブルーチンの先頭に制御を移す。gotoと違い、戻り番地を保存する。戻り番地の値はそれぞれ、制御を移す前の番地+3、制御を移す前の番地+5となる。
 ret - サブルーチンから呼び出し元の戻り番地に制御を移す。番地が格納されている局所変数を指定する。
 lookupswitch - switch文のcase式の値が不連続である場合に、値を探しながら飛び越し先を探し、飛び越しを行う。
 tableswitch - switch文のcase式の値が連続である場合に、（キーがインデクス値、値が飛び越し先番地の）表を使って飛び越しを行う。（高速である）

 メソッド呼び出し・復帰 
 invokevirtual - インスタンスメソッドを呼び出す。
 invokespecial - インスタンス初期化メソッド、プライベートメソッド、スーパークラスのインスタンスメソッドを呼び出す。
 invokestatic - クラスメソッドを呼び出す
 invokeinterface - インターフェイスメソッドを呼び出す。
 invokedynamic - Java 7でJava VM上で動作する動的プログラミング言語のために追加されたが、Java 8からはラムダ式の呼び出しにも使用されている。
 return - スタックに値を残さずに、呼び出し元の戻り番地に制御を移す。
 ireturn、 lreturn、 freturn、 dreturn、 areturn - スタックに int値、 long値、 float値、 double値を残して、サブルーチンの呼び出し元の戻り番地に制御を移す。

 型キャスト 
 checkcast - 参照値が指し示すインスタンスの型を確認。
 instanceof - スタックから参照値をpopし、それが指定された型と同じであれば1を、異なれば0をスタックに積む。
 i2l、 i2f、 i2d、 i2b、 i2c、 i2s - int値をlong値、 float値、 double値、 byte値、 char値、 short値に変換したものをスタックに残す。
 l2i、 l2f、 l2d - long値をint値に、 float値に、 double値に変換したものをスタックに残す。
 f2i、 f2l、 f2d - float値をint値に、 long値に、 double値に変換したものをスタックに残す。
 d2i、 d2l、 d2f - double値をint値に、 long値に、 float値に変換したものをスタックに残す。

 比較演算 
 dcmpg、 dcmpl - double同士を比較し、1（大きい）、0（等しい）または-1（小さい）をスタックに残す。「-g」と「-l」の違いはオペランドがNaNだったときの扱いの差。（以下同様）
 fcmpg、 fcmpl - float同士を比較する。
 lcmp - long同士を比較する。

 算術演算 
 iinc - intの値を、符号付き1バイト（値の範囲は-128～127）の直接記述した定数だけ（符号付きで32ビットに拡張したうえで）増減する。
 iadd、 ladd、 fadd、 dadd - int値、 long値、 float値、 double値 で、スタックから取りだした第一の値に第二の値を加え、スタックに積む。
 isub、 lsub、 fsub、 dsub - int値、 long値、 float値、 double値 で、スタックから取りだした第一の値から第二の値を引き、スタックに積む。
 imul、 lmul、 fmul、 dmul - int値、 long値、 float値、 double値 で、スタックから取りだした第一の値に第二の値を掛け、スタックに積む。
 idiv、 ldiv、 fdiv、 ddiv - int値、 long値、 float値、 double値 で、スタックから取りだした第一の値を第二の値で割った商を、スタックに積む。
 irem、 lrem、 frem、 drem - int値、 long値、 float値、 double値 で、スタックから取りだした第一の値を第二の値で割った余り（value1 - (value1 / value2) * value2）を、スタックに積む。
 ineg、 lneg、 fneg、 dneg - int値、 long値、 float値、 double値 で、スタックから取りだした値の符号を反転した値（たとえば入力が123なら-123、-123なら123、0なら0）（すなわち2の補数）をスタックに積む。

 論理演算 
 ishl、 lshl - int値、 long値 を指定ビットだけ左にシフトした値をスタックに残す。
 ishr、 lshr - int値、 long値 を指定ビットだけ右に算術シフトした値をスタックに残す。負数はシフト後も負に維持される。
 iushr、 lushr - int値、 long を指定ビットだけ右に論理シフトした値をスタックに残す。
 iand、 land - int値、 long値 の2オペランドのAND（ビットごとの論理積）を求め、スタックに残す。
 ior、 lor - int値、 long の2オペランドの OR（ビットごとの論理和）を求め、スタックに残す。
 ixor、 lxor - int値、 long の2オペランドのXOR（ビットごとの排他的論理和）を求め、スタックに残す。

 オブジェクト 
 new - インスタンスの生成
 putfield、 getfield - メンバ変数への値の代入、値の取り出し
 putstatic、 getstatic - クラス変数への値の代入、値の取り出し

 配列 
 iaload、 laload、 faload、 daload、 aaload、 baload、 caload、 saload - 配列の指定された位置にあるint値、 long値、 float値、double値、参照値、byteまたはboolean値、char値、 short値をスタックに残す。
 iastore、 lastore、 fastore、 dastore、 aastore、 bastore、 castore、 sastore - 配列にint値、 long値、 float値、 double値、 参照値、 byteまたはboolean値、 char値、 short値を格納する。
 newarray - 数値や文字の配列を作成し、その参照値をスタックに残す。
 anewarray - 参照値の配列を作成し、その参照値をスタックに残す。
 multianewarray - 多次元配列を作成し、その参照値をスタックに残す。
 arraylength - 配列の長さを求め、スタックに残す。

 その他 
 athrow - java.lang.Throwableのインスタンスで例外やエラーを発生させる。
 nop - 何もしない ()。
 breakpoint - デバッガがブレークポイントの実装に使える命令。
 monitorenter - オブジェクトのモニタをロックする。既に他のスレッドにロックされていれば待たされる。 
 monitorexit - オブジェクトのモニタをアンロックする。他のスレッドのロック待ちは再度試行される。
 wide - ロード／ストア系命令やret、iincのインデックスを16ビットに拡張する。iincでは定数も16ビットに拡張する。

 実装系 
エンタープライズ用（デスクトップ用を包含）としては、オラクル、IBM、HPなどの各社から実装系がリリースされている。オペレーティングシステム (OS) 上でアプリケーションとして動作する形態が一般的である。

Windowsにも標準でJava仮想マシンが実装されていたが、マイクロソフトがサン・マイクロシステムズとの契約に反して自社仕様の拡張機能を付加したため、Windows XP以降のOSではJavaの技術使用ライセンスを失った。

また、オープンソースコミュニティの手によってIKVM.NETという共通言語ランタイム上で動作するJava仮想マシンの実装も進められている。

変わった試みとしてGNU SmalltalkのVM上で構築されたJava仮想マシンが存在する。

picoJava, Jazelle などJava仮想マシンの命令がハードウェア実装されたプロセッサ、すなわちバイトコードを直接実行可能なプロセッサも存在する。

 JITコンパイル 
最初のJava仮想マシンの実装 (JDK 1.0) はインタプリタ型であったため、動作速度が他のアプリケーションに比べて遅い場合があった。そのため、メソッドの実行直前 (Just in Time) にバイトコードをCPUのネイティブコードにコンパイルして実行する形式（JITコンパイラ）を、ボーランドや IBMなどがリリースした。サン・マイクロシステムズの実装もJDK 1.1からJITコンパイラを搭載した。

加えて、JDK 1.2から、サン・マイクロシステムズはHotSpotという高速化技術を導入した。HotSpotはJITコンパイラの一種だが、常にJITコンパイルを行うのではなく、実行回数が規定回数を超えたメソッド (Hotspot) のみをJITコンパイルする。これにより、JITコンパイルによる無駄なリソースの消費を防いだり、インタプリタ実行時のプロファイリング情報をJITコンパイル利用できる利点がある。HotSpotには用途別に、クライアントVM（コンパイルは高速だが生成されるネイティブコードが相対的にあまり最適化されない）と、サーバVM（コンパイルは低速だが生成されるネイティブコードが相対的により最適化される）がある。

 スレッド 
 グリーンスレッド - OSが提供するスレッドライブラリ（pthread等）を直接使わずJavaで仮想的なスレッドを作り実行する形式。現在は利用されていない。
 プラットフォーム・スレッド - OSスレッドとJavaスレッドが1対1で対応する形式。
 仮想スレッド - OSスレッドをブロックせずに多数の並行タスクを扱える、Java VMが管理する軽量スレッド。Java 21（JEP 444）で導入。

 ガベージコレクション 
 ガベージコレクションには、JDKは世代別ガベージコレクション（ヒープを2つ以上の世代に分割し、それぞれに異なるアルゴリズム（およびデータ構造）を適用する方式。詳しくは世代別ガベージコレクションの記事を参照）を採用し高性能化を図った。

 脚注 

 関連項目 

動作環境
Apache Harmony
Dalvik仮想マシン
HotSpot
IcedTea
IKVM.NET
Kaffe
leJOS
SableVM

 外部リンク 
The Java Virtual Machine Specification -Java SE 25 Edition- 

*
カテゴリ:Java
カテゴリ:Java specification requests