FE EXAM

JITコンパイラ(Just In Time)

実行時に中間コードを機械語へコンパイルして高速化する仕組み。

INTERACTIVE VISUALIZATION
解釈実行
ホットスポット
機械語
フェーズ
idle
実行モード
インタプリタ実行
体感速度
▮▮▯▯▯
シナリオ
ステップ1 / 6
STEP 1/6中間コードを受け取るプログラムはまず、特定のCPUに依存しない「中間コード(バイトコード)」の形で渡されます。3つの処理ブロックがあり、中でも loop(繰り返し処理)は何度も実行される予定です。中間コードはそのままではCPUが直接実行できないので、何らかの方法で動かす必要があります。
中間コード(バイトコード)の命令ブロック実行回数initインタプリタで解釈実行解釈0loopインタプリタで解釈実行解釈0finishインタプリタで解釈実行解釈0実行回数がしきい値を超えた loop が機械語へコンパイルされ、速くなる
JITの動き方
① 解釈実行
まずインタプリタで起動。待ち時間なしで素早く動き出す
② 検出・コンパイル
よく使う部分を見つけ、実行中に機械語へ翻訳する
③ 直接実行
以降はコンパイル済み機械語を直接実行して高速化
解説

📌
JITコンパイラとは

中間コード実行中JIT機械語に変換高速実行Just In Time = ちょうど必要なときに翻訳

JITコンパイラとは、プログラムの実行時に、中間コードを機械語へコンパイルして高速化する仕組みです。JITは Just In Time(ちょうど必要なときに)の略で、「動かしている最中に、必要になったところを翻訳する」という意味が込められています。中間コード(=特定のCPUに依存しない中間表現)を、CPUが直接理解できる機械語へ変えるのがポイントです。

身近な例で考えると、同時通訳に似ています。最初は1文ずつその場で訳していきますが(インタプリタ)、何度も同じフレーズが出てくるとあらかじめ訳文を用意しておき、次からはそれをすぐ読み上げます。よく使う部分だけ先に翻訳しておくことで、全体がスムーズになります。

上のツールで▶ボタンを押すと、最初はインタプリタで動いていたプログラムが、よく使う loop 部分を機械語化して速くなっていく流れを確認できます。

🚀
実行時コンパイルの利点

実行しながらコンパイルすることには、事前にすべてを翻訳しておく方式にはない利点があります。
必要な部分だけ高速化:頻繁に実行される部分(ホットスポット)だけを機械語化するので、無駄なコンパイルを避けられる
実行環境に最適化:実際に動かしている最中の情報(どの分岐をよく通るかなど)を使って、その環境に合った最適化ができる
起動が速い:最初はインタプリタで動き出すので、コンパイルの待ち時間なしですぐ起動できる

ここでホットスポットとは、プログラムの中でとくに何度も実行される部分のことです。たとえば何万回も回るループは、1回しか実行されない初期化処理よりずっと重要です。JITはこういう「効果の大きい部分」を狙い撃ちして速くします。

よく通る道だけを舗装する道路工事に似ています。すべての道を舗装するのは大変ですが、交通量の多い幹線道路だけを優先して舗装すれば、少ない手間で全体の流れが大きく改善します。Javaの実行環境などで、この仕組みが広く使われています。

⚖️
AOTとの違い

コンパイルのタイミングには、JITと対になるAOTAhead Of Time=事前に)という考え方もあります。AOTは実行する前にあらかじめ機械語へコンパイルしておく方式です。
AOT:実行前に事前コンパイル。起動が速いが、最適化は実行前の静的な情報に基づく
JIT:実行中にコンパイル。起動後に徐々に速くなり、実行時の情報で最適化できる

項目AOT(事前)JIT(実行時)
コンパイル時点実行前実行中
起動の速さ速い速い(まずは解釈実行)
最適化静的(実行前の情報のみ)実行時情報を使える

料理にたとえると、AOTは開店前にすべて仕込んでおくイメージで、注文後すぐ出せます。JITは注文を受けてから、よく出る人気メニューだけ作り置きしていくイメージで、営業を続けるほど提供が速くなります。どちらが良いかは、起動速度と実行速度のどちらを重視するかで使い分けます。

🔀
インタプリタとコンパイラのいいとこ取り

インタプリタすぐ起動・遅いコンパイラ準備要・速いJITすぐ起動・後から速い

JITを理解するには、まずインタプリタとコンパイラの違いを整理すると分かりやすいです。
インタプリタ(=逐次実行方式):ソースコードを1行ずつ読みながらその場で実行する。待ち時間なしですぐ動き出せるが、毎回読み直すので速度が出にくい
コンパイラ(=事前変換方式):実行前にまとめて機械語へ変換しておく。変換に時間がかかるが、実行は速い

JITはなぜ両方の良さを得られるのか。秘密は「まずインタプリタで動かして、あとから必要な部分だけコンパイルする」という2段階の戦略にあります。
起動時:インタプリタで即座に動き始める(コンパイルの待ち時間なし)
実行中:よく使われる部分(ホットスポット)を見つけ次第、機械語に変換する
変換後:以降はコンパイル済みの速い機械語で動く

スポーツの練習に例えると、まず試合に出てみて(インタプリタ)、何度も使う技だけ集中特訓する(JITコンパイル)イメージです。全部を特訓してから出場するのではなく、実戦で必要と分かった技術を後から強化するから効率的なのです。

📈
なぜ動かしながら速くなるのか

時間(プログラムの実行時間)起動時HOT検出回数カウントJITコンパイル機械語生成キャッシュ保存高速実行機械語で直接動く

JITが「動かしながら速くなる」仕組みを、4つのステップで見てみましょう。
① 起動時:インタプリタがプログラムを1行ずつ解釈して実行する。速度は普通
② ホットスポット検出:「この部分は何度も呼ばれている」と実行回数を数えて把握する
③ JITコンパイル:しきい値(基準の回数)を超えた部分を機械語に変換し、保存しておく
④ 高速実行:次からはコンパイル済みの機械語をそのまま使うので速い

なぜ全部を最初からコンパイルしないのか。プログラムの中には1度しか実行されない部分も多いからです。起動処理や初期化などは使い捨てで、コンパイルしても恩恵が少ない。JITは「実際に何度も使われたという実績のある部分だけ」に絞ってコンパイルするので、コストに見合った高速化ができます。これが、全てを事前コンパイルするAOTには真似できないJITだけの強みです。

練習問題

🎯
基本情報技術者 練習問題

Q1.JITコンパイラの説明として最も適切なものはどれか。
A.実行前にプログラム全体を機械語へ翻訳しておく仕組み
B.実行時に中間コードを機械語へコンパイルして高速化する仕組み
C.ソースコードの文法を検査する仕組み
D.実行ファイルを主記憶へ読み込む仕組み
Q2.JITコンパイラが「ホットスポット」を検出する目的はどれか。
A.エラーが起きた箇所を特定するため
B.よく実行される部分だけを機械語化して効率よく高速化するため
C.メモリの空き容量を増やすため
D.ソースコードを暗号化するため
Q3.AOTコンパイルとJITコンパイルの違いとして正しいものはどれか。
A.AOTは実行中、JITは実行前にコンパイルする
B.AOTは実行前に事前コンパイルし、JITは実行中にコンパイルする
C.両者に違いはない
D.JITは中間コードを使わない

関連コンテンツ