JVMのメモ

Java Virtual Machine Specificationを中心としたJVMに関するメモ。

実行時データエリア

ここではあくまでJava Virtual Machine Specificationの解釈とする。

「実行時データエリア」は実行時にJVMがどんなふうにデータを管理していくのかということ。Javaではクラスファイルがメモリにロードされて動くことになるが、クラスファイルの中でもそれぞれのデータ(static変数、フィールド、ローカル変数、メソッドなど)はライフサイクルや構造が異なる。よってJVM上のデータとしては細かく管理されることになる。

「Eden」「Metaspace」がでてくる(ブログなど)メモリモデルの解説もあるがそれらはおそらくHotSpotのことを指している。HotSpotなどはこれに準拠するかたちで独自のメモリ構造の考え方を持っている(のでここの説明とは異なる部分がある)。

構造

次の6種類に分けて考えられている。

JVMの実行時データエリア
Figure 1. JVMの実行時データエリア
プログラムカウンタレジスター(The pc Register)

各スレッドが現在どの命令を実行しているかの情報を保持する領域。スレッドごとに作られる。

JavaVMスタック(Java Virtual Machine Stacks)

各スレッドの実行時のスタック。メソッド呼び出しが行われるとスタックフレームが作られる。またローカル変数もここに保存される。

ヒープ(Heap)

各インスタンスとインスタンス変数(フィールド)が保持される。GCによって回収される。heapの英語の意味は「積み重ね」「かたまり」など。

メソッドエリア(Method Area)

static変数の値が保持される。

実行時コンスタントプール(Run-Time Constant Pool )

調査中。

ネイティブメソッドスタック(Native Method Stacks)

ネイティブメソッドコールのスタック。Java仮想マシンの実装では、ネイティブメソッド(Javaプログラミング言語以外の言語で記述されたメソッド)をサポートするために、「Cスタック」と呼ばれる従来のスタックを使用できる。

例外

実行時データエリアの構造から次の2つの例外が投げられる可能性がある。

java.lang.StackOverflowError

JavaVMスタックではメソッド呼び出しごとにスタックフレームを作るので(終わらない再帰呼び出しなどによる)度を超えた呼び出しをしてしまうとこの領域がパンクするため、JVMがjava.lang.StackOverflowErrorを投げることになる。ネイティブメソッドスタックもスタックなのでその可能性がある。

なので、再帰呼び出しするにしても必ず終わるようにしなければいけない。

java.lang.OutOfMemoryError

JavaVMスタックなどはスレッドの実行が終了すればデータとしては減っていくことになるが、ヒープについてはGCされない限りは残る。そのときに次のオブジェクトを作る領域がないと判断されればJVMがjava.lang.OutOfMemoryErrorを投げることになる。

なのでjava.lang.OutOfMemoryErrorが発生した場合は、ヒープが増えすぎないようにプログラムを見直したり(ムダにnewしてないかとか)、ヒープの実メモリ割り当てを増やすみたいな対策をとることになる。

JVMの実装

(2017年現在)HotSpotがかなりのシェアを持っていると思われるがOpenJ9なんかも注目。

HotSpot

Oracle社提供のVM。OracleからJDKをダウンロードした場合はこれ。java -versionのコマンドを実行するとHotSpotとでてくる。

JRockit

これもOracle社提供のVM(だった)。Java SE 7 からHotSpotにマージされた。

IBM J9

IBMのJVM。WebSphere、DBの標準VMとして利用されている。

OpenJ9

IBM J9をオープンソース化するもの。Java SE 9に合わせて正式リリース予定。

アンドロイド(Dalvik/ART)について

Javaでコードは書けるが、Javaのバイトコードで動くのではなく.dex形式にしてしまうなどJava Virtual Machine Specificationは準拠していないと考えられる。なのでAndroid Javaみたいないいかた(理解)をされる。

Appendix B: 改訂履歴

  • v1.0, 2016-07-23: 初稿