MENU

JVMの設計思想と実装系をHotSpot中心に整理する

JVM アイキャッチ
JVM

JVMはJava Virtual Machineの略で、1995年にSun Microsystemsが発表したJava言語の実行基盤として登場しました。Javaソースコードをコンパイルして得られるバイトコードをプラットフォーム横断で動かす仕組みであり、「Write Once, Run Anywhere」というスローガンの技術的裏付けを担ってきた存在です。現在はOracleが管理するOpenJDKを中心に、Eclipse Adoptium、Amazon Corretto、Azul Zuluなど複数のディストリビューションが流通しており、JavaだけでなくKotlin、Scala、Clojureなど多くの言語が同じVM上で動いています。

目次

この記事の目次

  1. バイトコードとクラスファイルの仕様
  2. HotSpotが切り開いた適応的最適化
  3. 多言語ホストとしての側面
  4. 運用と性能チューニングの勘所
  5. まとめ

バイトコードとクラスファイルの仕様

バイトコードとクラスファイルの仕様

JVMが直接解釈するのはJavaソースコードではなく、コンパイル後に生成されるクラスファイルです。クラスファイルはマジックナンバー0xCAFEBABEで始まる固定フォーマットを持ち、定数プール、フィールド情報、メソッド情報、属性情報といった構造を順に並べた形をしています。メソッド本体には約200種類のオペコードからなるスタックベースのバイトコードが格納され、VMはこれを一命令ずつ取り出して評価スタックを操作することで処理を進めます。

スタックベースを採用した理由には、レジスタ割付を実装側の自由に委ねたいという設計判断があります。1995年当時のJavaは家電組込み向けに構想されていたため、命令セットは命令長が短く解釈実行でも妥当な速度が出る形に揃えられました。後年のJITコンパイラはスタック表現を内部でレジスタ表現へ変換したうえで最適化と機械語生成を行うため、表面的な低速さは隠蔽されます。この層構造があるため、新しい言語フロントエンドはバイトコードさえ出力できれば既存のVMをそのまま利用できます。

HotSpotが切り開いた適応的最適化

HotSpotが切り開いた適応的最適化

現在主流の実装系HotSpotは、もともとLongview Technologiesという小規模企業が開発した処理系を、1997年にSunが買収して取り込んだ系譜を持ちます。1999年にJDK 1.3に統合され、実行頻度の高いメソッドを動的に検出して機械語化する適応的最適化を標準機能としました。C1と呼ばれるクライアントコンパイラとC2と呼ばれるサーバコンパイラが用意され、短時間で軽量な最適化を行うC1と、より長時間をかけて深い最適化を行うC2を段階的に切り替えます。

HotSpotにはGarbage-FirstガベージコレクタG1、低遅延を狙うZGCやShenandoahといった多様なGC実装が同梱されており、用途に応じて選択できることがJVMの大きな魅力となっています。ZGCは2018年のJDK 11で実験的に導入され、2021年のJDK 15で正式版となり、テラバイト規模のヒープでも一時停止を10ミリ秒程度に抑える性能を実現しました。Shenandoahはレッドハットが開発を主導しており、こちらも低遅延を志向した世代別GCとしてJDK 12以降で利用可能になっています。利用者は起動時オプションで切り替えるだけで恩恵を受けられます。

多言語ホストとしての側面

多言語ホストとしての側面

JVM上で動く言語はJavaだけにとどまりません。Scalaは2003年にスイス連邦工科大学のMartin Oderskyが発表し、Kotlinは2011年にJetBrainsが発表したのち、2017年にGoogleがAndroid公式言語に採用しました。Clojureは2007年にRich Hickeyが設計したLisp系言語、Groovyは2003年に登場した動的言語で、いずれもバイトコードへコンパイルされる形でJVMの最適化や成熟したGCの恩恵を受けています。JRubyやJythonのように既存スクリプト言語のJVM移植版も古くから存在しています。

2011年のJDK 7で導入されたinvokedynamic命令と、その前後で整備されたMethodHandlesは、動的型付け言語をJVM上で効率的に実装するための鍵となる機能でした。Java自体のラムダ式や、ScalaのトレイトのデフォルトメソッドもこれらAPIに依存しており、多言語ホストとしての性格を強化する設計判断として現代まで影響を与え続けています。業務システムでJVMを採用する理由には、こうした言語選択の自由度も含まれていることを意識しておくとよいでしょう。

運用と性能チューニングの勘所

運用と性能チューニングの勘所

JVMの運用ではヒープサイズ-Xmxとメタスペース-XX:MaxMetaspaceSize、GCアルゴリズム、JITコンパイル閾値といった起動オプションが性能を大きく左右します。デフォルト値は多くのワークロードで妥当に振る舞いますが、巨大なヒープを扱うバッチ処理や、p99レイテンシを厳しく管理したいオンライン処理では、GCログとJVM Flight Recorderを使った実測ベースのチューニングが欠かせません。観測ツールとしてはJDK Mission Controlが標準として提供されています。

コンテナ環境ではJDK 10以降にcgroupからのCPUとメモリ制限を自動認識する機能が入り、それ以前のバージョンで顕在化していた「ホスト側のCPU数を誤検出して並列度を過大に設定する」という典型的な落とし穴が解消されました。Kubernetes上で運用する場合は、JVMヒープとコンテナのメモリ制限の比率を経験的に60〜75パーセント程度に抑える運用が広く行われています。GraalVMによるネイティブイメージ化や、CRaCと呼ばれるチェックポイント復元技術も登場し、「JVMは起動が遅い」という従来の弱点に対する代替策が広がりつつあります。

まとめ

JVMは30年に及ぶ進化のなかで、適応的最適化、低遅延GC、多言語ホスト、ネイティブイメージ化など、実行基盤として求められる要素を一通り取り込んできました。現代の業務システムでJavaを採用するかどうかは、しばしばJVMという基盤への投資をどう活かすかという問いに帰着します。

※本記事はIT用語辞典の手書きドラフトです。公開前に最新情報・出典を確認のうえ加筆修正してください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次