2024.07.18

JVM徹底解剖

Frank Delporte
Azulのシニアテクニカルライター兼Javaチャンピオン
このエントリーをはてなブックマークに追加

Javaは単なるプログラミング言語ではありません。ツール、ランタイム、さらにはコミュニティ全体をカバーする「傘」なのです。この記事では、その傘下の一部であるJava仮想マシン(JVMについてお話したいと思います。正確にはどのようなもので、どのように機能するのでしょうか?

Javaは、最も人気のある言語の中でも常にトップの地位を保っています。この本当の理由は言語そのものではなく、JVMにあります。そしてJVMが開発者に与える力が、不動な人気を支えています。(Simon Ritter、Azulの副CTO)

JDK、JRE、JVMの違いを理解する

ソフトウェアの世界には略語があふれています。このため、混乱を招き、特定の用語の誤用につながる可能性があります。まず次の用語の違いを理解する必要があります。

azul_202407_thumb.png

JDKとは:Java開発キットのこと

JDKはJavaエコシステムの最高レベルにあります。JDKは、その他すべての「ソース」です。毎回リリースされる「新しいJavaバージョン」とは、改善、バグとセキュリティの修正、新規または削除されたツールを含む、JDKの新しいバージョンのことです。JDKは、以下の複数のコンポーネントで構成されています。

      • JVMとはJava仮想マシンのことです。実行可能なjavaで、アプリケーションを実行します。JVMが機能する方法について、さらに詳しく説明します。
      • Javaアプリケーションの開発に使用するライブラリは、5,000を超えるクラスのセットで、java.util、java.text、java.nio、java.sqlなどを含んでいます。
      • 一連のツールには、Javaアプリケーションの作成、モニタリング、実行に役立つ、以下のようなツールが含まれています。
        • javac:Javaクラスをバイトコードにコンパイルします。
        • javadoc:JavaソースファイルからAPIドキュメンテーションのHTMLページを作成します。
        • jshell:ShellターミナルでJavaコードと対話し、実行します。
        • 他にも様々なツールがあります。

JREとは:Javaランタイム環境のこと

Java 9までは、各JDKには付属のJREがあり、この中には同じJVMとライブラリが含まれていましたが、限られたツールセットしか含まれていませんでした。このため、JDKのサブセットにすぎませんでした。JREの目標は、すべてのツールによるオーバーヘッドなしにアプリケーションを実行するデバイス上で使用され、ダウンロードして配布するファイルを小さくすることでした。しかし、Java 9でモジュールが導入され、ランタイムをjlinkで構築できるようになりました。アプリケーションの実行に必要なモジュールのみが含まれるので、JDKやJREと比較してはるかに小さいランタイムを作成できるようになりました。

多くの組織は依然としてJREのアプローチに依存しているため、Azulやその他のプロバイダーは現在も新バージョンのJREを作成しています。利用可能なJREをすべて記載したリストについては、Azul Coreダウンロードページをご覧ください。

一度書けば、どこでも実行可能

Javaがリリース当時から約束していた機能です。開発者は、単一のコードベースを作成するだけで、オペレーティングシステム(Windows、Mac、Linuxなど)とハードウェア(x86、ARM、aarch64など)の両方を含む、任意のプラットフォームでプログラムを実行できます。そのためには、Javaコードをバイトコードに変換する必要があります。これは開発者の仕事であり、この作業にはjavacをMavenやGradleのようなビルドツールを通じて使用します。このバイトコードは、JVMがマシン上で実行します。つまり、どのクラスでも、すべてのプラットフォームで実行可能です!

そのためには、特定のネイティブコードが必要な、サポートされているオペレーティングシステムおよびプラットフォームそれぞれに対して、JVMバイトコードを「変換」する必要があります。つまり、様々なプラットフォームをサポートするために開発者として作成する必要がある、それぞれ異なる実装がすべて、Javaシステムの開発者によってすでに処理されているのです。ソースコードを見れば、Javaプロジェクト内でどのように実行されるのかが分かります。このコードはすべて、GitHubで無料で入手できます。たとえば、このリンクでは、HotSpotの様々な実装を見ることができます。プロジェクトのスクリーンショットを以下に示します。

azul_202407_02.png

azul_202407_03.png

ジャストインタイムのコンパイル

アプリケーションが起動すると、JVMのテンプレートモデルを使用して、バイトコードがプラットフォーム指示に直接変換されます。この時点では、最適化はまだ実行されていないため、Javaの実行は同様のコンパイルされたネイティブコードよりも遅くなります。しかし同時に、JVMは各メソッドが呼び出される頻度を即座に追跡します。事前に定義されたしきい値(HotSpotとしても知られています)に達すると、JVM内のジャストインタイム(JITコンパイラは、2つのフェーズで作業を開始します。

      • C1 JIT:ネイティブコードへの最初の変換です。
        • メソッドがHotspotとして検出されると、コードはネイティブコードに再コンパイルされます。
        • これは最小限の最適化によって可能な限り速く実行され、このネイティブコードの使用と同時に、JVMによって再度プロファイリングされ、その使用方法を理解することができます。

  • C2 JIT:可能な限り最高の最適化を実現します。

        • 再び特定のしきい値に達すると、JVMはネイティブコードへの新たな再コンパイルを実行します。しかし、最高のパフォーマンスに達するためのプロファイリングを考慮するため、最大のパフォーマンスに達するまでにはさらに時間が必要です。
        • この時点で、生成されたネイティブコードは、コードの使用方法と完全に一致しています。
        • つまり、コードが実行されている環境、処理する必要があるデータ、コードの実行をトリガーするイベントなどに応じて、同じコードでも異なるネイティブコードが生成される可能性があります。
        • Azul Zulu Primeには、C2の代替機能が含まれています。Falcon JITは、オープンソースプロジェクトLLVMを基盤とし、ほとんどの場合、従来のC2と比較してコードのパフォーマンスが向上します。詳細については、AzulドキュメントのFalcon コンパイラの使用」をご覧ください。

以下のグラフを見ると、解釈されたバイトコード(黄色)から最初の最適化されたコード(C1、緑色)にシフトすると、アプリケーションの速度がどのように上がり、最適化されたコード(C2、青色)で最高のパフォーマンスに到達することが分かります。このトピックと、以上の各ステップを改善するためにアプリケーションを「チューニング」する方法の詳細については、「ウォームアップの分析とチューニング」をご覧ください。

azul_202407_04.jpg

(↑JITは、Ahead-Of-TimeAOTの対局にあり、通常、生成されたネイティブコードが実際のニーズに合わせて最適化されると、動作が改善されます。)

バイトコードがネイティブコードに変換されるプロセスについての詳細は、Simon Ritterによる次のブログを参照してください。 

メモリ管理

JVMのもう1つの役割は、自動メモリ管理です。C、C++などの他のプログラミング言語では、開発者はメモリの割り当て(malloc)と解放を行う必要があり、この作業を正しく実行しない場合は、メモリの問題が発生する可能性があります。ガベージコレクター(GC)は、この作業を処理するJVMの一部です。GCにより、開発者はメモリの使用管理の心配から完全に解放されます。GCは、コードから参照されていない不要になったオブジェクトを定期的に検索し、メモリ領域を解放して再利用できるようにします。

ガベージコレクターに関する記事は、すべて以下からご覧いただけます:Java開発者がガベージコレクションについて知っておくべきこと

azul_202407_05.jpg

スレッド管理

スレッド管理とスレッド間の対話の管理も、JVM関連のトピックです。

OpenJDK 19には、Project LoomとVirtual Threadsの最初の評価バージョンが含まれており、オペレーティングシステムのスレッドから独立した、Java内部のマルチレベルスレッドが導入されています。このため、Javaにおけるスレッドの使用方法に新たなダイナミズムが加えられます。オペレーティングシステムのスレッド数に依存しないため、効率が大幅に上がり、スケーラビリティとストリーミングまたはメッセージングアプリケーションに大きな影響を与えます。

詳細については、以下をご覧ください:JDK 19の概要と、Javaユーザーに必要なJDK 19の知識

静的型付け言語と動的型付け言語

Javaに関連してよく聞かれるもう1つの用語は、Javaの特性を表す「静的型付け言語」です。「静的」とは、変数が使用される方法を指します。新しい値を宣言するときは、型を定義する必要があり、型は後で変更できません。たとえば、String label = "Hello, World!"とした場合、後でlabel変数に数値を割り当てることはできません。たとえばJavaScriptには、このようなルールはありません。動的型付け言語の使用に慣れた、Javaを始めたばかりのプログラマーは混乱するかもしれませんが、静的型付けはコード実行時の多くの問題やバグを防ぐことができます。

「静的」は値の定義方法に関連していることに注意してください。対照的に、クラスは実行時に「動的」な方法でロードされるからです!これにより、アプリケーションは環境や特定の設定に応じて正しく動作できるようになります。たとえば、環境設定に基づいて、テスト中と本番中で異なるデータベースを使用できます。いずれの場合も、他のクラスを動的にロードしてデータベースと対話できます。

「OpenJDKのAzulビルド」とは?

Javaランタイムは、すべて同様に動作する必要があるため、ユーザーが使用しているJDKに関係なく、アプリケーションは確実に同じ結果を出します。そのためには、全ディストリビューションが、Java Community Process(JCP)を通じて、関連するJava Specific Request(JSR)によって定義されたJava SE仕様に準拠する必要があります。

その検証として、ディストリビューションは、Java Technology Compatibility Kit(TCK)のテストにすべて合格する必要があります。ただし、ディストリビューションの大半はOpenJDKに基づいていますが、すべてのディストリビューションが同じ方法で実装されているというわけではありません。Azulが提供する2つのディストリビューションは、TCKに準拠していますが、互いに大きく異なります。

OpenJDKのAzul Zuluビルド(別名Zulu)

  • OpenJDKのこのビルドは、OpenJDKとほぼ同じです。
  • 機能的な変更はありません。
  • しかし、古いバージョンのバグが修正され、セキュリティが改善されています。たとえば、Azulは、現在でもJDK 7の新しいバージョンを作成し、セキュリティとバグ修正をJDK 7にバックポートしている唯一の販売代理店です。
  • Azulは、全バージョンにJREディストリビューションを提供しています。
  • さらにAzulは、ほぼすべての販売代理店がサポートを停止したバージョン(たとえば、JDK 7)を更新し、メンテナンスを充実させてリリースしています。
  • 以下は、現在リリースされている製品です。
  • OpenJDKAzul Zuluビルド
    • 任意のOpenJDKの完全互換品です。
    • 無料でダウンロードしてご利用いただけます。

  • Azul Platform Core
    • OpenJDKのAzul Zuluビルドにサポート、アップグレード、追加ツールが付属しています。
    • 評価および開発用の無料バージョンとライセンス版が用意されています。

OpenJDKのAzul Primeビルド(別名Prime)

  • このディストリビューションは、OpenJDKベースです。
  • ただし、以下の機能的な変更があります:
  • OpenJDKのガベージコレクター実装がすべて削除され、Azul C4ガベージコレクターに置き換えられました。
  • C2 JITコンパイラは削除されていませんが、Azul Falconコンパイラが追加されており、起動オプションでどちらを使用するかを選択できます。
  • 以下は、JDK内の追加機能です:
  • Connected Runtime Service(CRS)は、Azul Vulnerability Detectionに接続することで、リアルタイムでのセキュリティ課題の特定に役立ちます。
  • ReadyNow:Javaアプリケーションの起動にかかる時間を短縮し、高速での実行を継続するテクノロジーです。
      • Azul Platform Primeとしてリリースされています:
        • OpenJDKのAzul Primeビルド、C4、Falcon、ReadyNow、サポート、アップグレード、追加ツールのセット。
        • 評価および開発用の無料バージョンとライセンス版が用意されています。

Azul JDKディストリビューションは、Azul JDKのダウンロード」からダウンロードできます。

まとめ

JVMは、他の言語と比較して、開発者がやりたくないが、やらなければならない多くのタスクを処理します。そのおかげで、開発者はビジネスロジックと実際の実装作業に専念できます


関連リンク

Azul Systems公式サイト https://www.azul.com/ja/

Azul Platform製品紹介ページ

IT-EXchangeでAzul Plataformの詳しい製品説明をご覧ください。

この記事の著者:Frank Delporte

Azulのシニアテクニカルライター兼Javaチャンピオン

『Raspberry Pi でJavaを始める』の著者。2023 年にJava Championとしての地位を獲得しました。Pi4Jチームのメンバー、BeJUG Belgium Java User Groupの共同主催者であり、CoderDojo Belgium Ieperのリードコーチも務めています。 Friends Of OpenJDK (Foojay.io) への頻繁な寄稿者でもあり、Foojay ポッドキャストを制作しています。


DevOps Hubのアカウントをフォローして
更新情報を受け取る

  • Like on Feedly
    follow us in feedly

関連記事

このエントリーをはてなブックマークに追加

お問い合わせ

DevOpsに関することなら
お気軽にご相談ください。

Facebook、TwitterでDevOpsに関する
情報配信を行っています。