Javaが実行されるとき、サーバーの中で何が起きているのか。
パフォーマンスを考えるうえでは知っておきたい話だが、普段の業務ではあまり意識しない部分でもあるため、仕事納めが終わった年末に、自分なりにこのあたりを整理してみることにした。
なお、著者の知識レベルは以下のとおりです。
- 40歳・未経験からソフトウェア開発のエンジニアに転向して3年目
- Java SE 11 Silver / Gold を取得
- 応用情報技術者試験は午後がなかなか突破できず、その流れで受験した情報処理安全確保支援士試験に先日合格
- 応用情報の勉強再開
わからなかったことや、調べながら理解していった過程をできるだけ正直に書いています。
「一緒に整理してみるか」くらいの軽い気持ちでよんでいただき、「ここは違う」「この資料が参考になる」といったご指摘や情報のご共有いただけますととてもうれしいです。
ソースコードが実行されるまでの流れ
XX.java(ソースプログラム、ソースコード)
↓
↓(コンパイル)コンパイラ:javac XX.java
↓ →ここでのエラーは「コンパイルエラー」
↓
XX.class(バイトコード(中間コード))
↓
JVM(Java仮想マシーン)
↓ →ここでのエラーは「実行時エラー」
↓
OS、CPU
JVMはOS、プラットフォームごとに用意されている。
つまり、LinuxとmacはさらにARM64用とx64用が用意されているような感じ。
実際にJavaのダウンロードページを見るとOS、プラットフォームごとに
JDKが用意されているのがわかる。
JVMはJRE(Java Runtime Environment:Java実行環境)に含まれており、
JDK(Java Development Kit:Java開発環境)は、JERと開発に必要な環境をひとまとめにしたもの。
java silverではこんな感じで学べる。
参考にした本:「オラクル認定資格教科書 Javaプログラマ Silver SE 17」(翔泳社)
JVMがOS内で何をしているのか
Javaのパフォーマンスを考えるにはJVMが何をしているのかが重要だと思うけど教本などにはこの辺までは記載されていない。
JVMはバイトコード(XX.class)を解釈して、どうやってOSに命令しているのか?が最初疑問だったが、ChatGPTに、OS、CPUに命令してるわけではないと指摘された。
JVMは「OSに直接命令」しているわけではなく、最終的にはCPUが理解できる機械語を実行させています。
Javaソース
↓ javac
バイトコード (.class)
↓ JVM
├─ インタプリタ(逐次解釈)
├─ JITコンパイラ(機械語生成)
↓
ネイティブ機械語
↓
OS / CPU が実行
JVMは OSの上で動く「一つのプログラム」 です。
まとめ(超重要)
JVMは OS上のネイティブプログラム
バイトコードは JVM用の仮想命令
実行方法は2つ:
インタプリタ
JTT(機械語生成)
OSと直接やり取りするのは JVMだけ
Javaプログラムは 間接的にOSを使っている
一文で言うなら
JVMはバイトコードを解釈またはJITで機械語に変換し、
OS上で動く自分自身のプロセスとしてCPUに実行させている
応用情報で学習したCPUの内容と、ここでつながった。
CPUの命令実行過程
主記憶装置
↓
命令フェッチ:命令の取り出し
↓
デコード:命令の解読
↓
オペランドアドレス算出:
↓
オペランドフェッチ
↓
実行
CPUは機械語レベルの命令をメモリから取り出して、実行しているんだった。
参考:ニュースペックテキスト 応用情報技術者 2020年度
第3章ハードウェア 1.機械語命令の実行
まとめたいところだけど、JVMで色々調べる中、JVMのアーキテクチャについて一番わかりやすくまとめられていたのは以下だった。
ChatGPT曰く「JVM仕様書に書いてある概念を“元ネタの一部”として、一般的なJVM解説知識(特にHotSpot寄り)を混ぜて書いた記事」らしいので基本はおさえられそう。
また、JVMにはクラスローダーという仕組みがありそれもJVMを知るには重要なキーワードだと思う。
これについては以下が勉強になる。
JVMの実装
これを書き始めた時には気づいていなかったのだが、ChatGPTをサンドバックにしながら、JVMというのは、実は仕様で、実装されたJVMはいくつかあるらしいというのがわかってきた。
一番有名なのは
OracleJavaのHotSpot VM
HotSpot VMのコードベースは、これまで20年以上にわたり、数百人の人々によって開発されてきました。その規模は巨大で、約3000個のC/C++ヘッダーファイルとソースファイルで構成され、120万行を超えるコードで構成されています。クラスローダー、バイトコードインタープリタ、そしてサポートランタイムルーチンに加え、バイトコードからネイティブ命令に変換する2~3個のJITコンパイラ、少数のガベージコレクタ、そして同期処理などのための高性能ランタイムライブラリも含まれています。
HotSpot JVM は C/C++ のヘッダーファイルとソースファイルで構成されており、
JVM 自身は C/C++(および一部アセンブリ)で実装されている。
JVM 内部には、Java バイトコードを実行時に解析して
CPU アーキテクチャ向けの機械語を生成するロジック(JIT コンパイラ)があり、
生成された機械語は CPU により直接実行される。
この JIT を用いた実行時最適化により、パフォーマンスが向上している。
その他のJVM実装として有名なところ
パフォーマンスはJVMの仕様以外のところで、各製品やバージョンによって異なる、ということになるのかも。
より詳しく勉強する際は
・ JVMの仕様書
・パフォーマンスを重視するならHotSpotをはじめとする各製品ごとのJVMの理解
ってことになるのかな。