|
|
ジャストインタイムコンパイル (Just In Time Compilation、JITコンパイル、その都度のコンパイル)方式とは、 ソフトウェアの実行時にコードのコンパイルを行い実行速度の向上を図る方式であり、 動的コンパイルとも呼ぶ。通常のコンパイラはソースコード(あるいは中間コード)から対象言語への変換を実行前に(コンパイル時に)行う。これをJITと対比して事前コンパイル (Ahead Of Time, AOT)コンパイルと呼ぶ。
事前コンパイル方式と比べ、JIT方式ではコンパイル時間の分が プログラム実行時間に関するオーバーヘッドとなる。また、事前コンパイルで可能な、 高度で時間のかかる最適化を行うことは許されない。これは、実行速度を向上させるためにコンパイルするのだから、あまり時間がかかっては意味がないためである。
事前のコンパイルと比べてこのような不利な点を持ちながらも、 JIT方式が有用なのは、実行時にコンパイルを行うことで OS]やCPUに依存しないソースコードや中間コード の状態でソフトウェアを配布することができるからである。
JITを装備した処理系は、表面上はインタプリタとして動作するが、 内部でコンパイルを行い、メモリ上に生成した機械語コード(対象コード)が実行されるため、 インタプリタと比べると実行速度を向上することができる。この意味で、JITは CPUやOSに依存しない実行形式を配布できる、というインタプリタの利点を保ったまま、 実行速度が遅い、という欠点を克服しようとするものといえる。
| Table of contents |
|
2 適応的コンパイル(Adaptive Compilation) 3 JITコンパイル方式の利点 4 応用 5 JavaのJITコンパイラ |
JITコンパイルをメソッドのロード時や、クラスのロード時に行う場合、
プログラムの大幅な起動時間の低下がもたらされる。また、一般にコンパイル後の
コードはコンパイル前のコードより抽象度が低く、
コンパイル後のコードを保持するために必要なメモリ容量が大幅に増大する。
上のようなJITコンパイラの短所を補うためのJITコンパイルの一方式として
適応的コンパイルという方式がある。これは、起動当初はインタプリタとして実行し、
よく呼び出されるメソッドや繰り返し実行されるコードの検出(プロファイリング)を行い、
そのようなコードのみをコンパイルする、というものである(このとき、コードが
使われた時にすぐにコンパイルするのではなく、何回か呼ばれた後に遅らせてコンパイル
を行うのが、このことを遅延コンパイル(Lazy Compilation)と呼ぶ)。
一般にプログラムの実行においてその実行時間の
大半はプログラム中のごく一部において費やされる、という経験則がある
(実際の比率については状況に依存するが、
典型的にはコードの実行時間の80%は20%のコードにおいて費やされる
といわれ、80-20の法則と呼ばれる)が、適応的コンパイルにおいては
実行時間の大半が費やされるような、ボトルネックとなるコードのみをコンパイルすることで、
起動時のオーバーヘッドや利用メモリ増大を抑えたうえで、
効率よく実行速度を向上することができる。
この適応的コンパイルによる適応的最適化(Adaptive Optimization)は、静的コンパイルでは得られない情報を元に最適化が行えるため、静的コンパイルより、むしろパフォーマンスが上がる場合もある。
JITコンパイル方式と事前コンパイルの生成コードの質を比べると、
前述のようにコンパイル時間に対する制約のためJIT方式の方が不利であるが、
有利な点もある。それは、実行環境を知った上でそれに応じた生成コードの選択や
最適化を行うことができるということである。
Intel社のx86CPUを例にとって見ると、IA32アーキテクチャの
範囲内でもそれぞれの世代でさまざまに命令が拡張されてきているが、
アプリケーションコードの後方互換性を保持する場合、
実行バイナリ中では386と互換の命令しか使うことができない。
つまり、MMX PentiumのMMX命令を含んだコードは
80386やPentiumでは実行できない。しかし、JIT方式では、
CPUがMMXをサポートしているならMMX命令を使ったコードを生成し、
そうでなければ多少効率の悪いPentiumの命令の
範囲内での実行を行う、ということができる。
また、実行環境におけるキャッシュやメモリのサイズ、
速度特性なども実行時にならないと最終的にはわからない。JITコンパイル方式では
実際に走行しているCPUやメモリの情報を知ることができるため、
それに応じたコードを生成することができ、事前コンパイルよりも
優れたコードを生成できる可能性がある。
さらに、オブジェクト指向言語の実行においては
仮想メソッドの呼び出しは仮想関数表を経由した間接呼び出しになるが、
動的コンパイルにおいては、そのメソッドをオーバーライド定義したサブクラスが存在しない限り、
間接呼び出しを静的束縛として呼び出したり、あるいはインライン展開することができる
(そのメソッドをオーバーライドするサブクラスが動的にロードされる可能性があるが、その場合はこのコンパイルされたメソッドは最適化戻し(deoptimize)される必要がある)。
JIT処理はJava技術の普及に伴い広範囲に使われるようになったが、
JavaのHotspot技術はSunにおけるSelf言語での動的コンパイル技術研究に基づいており、
それに先立つ商用Smalltalk処理系でもJITコンパイル技術は確立されていた。
JIT技術はトランスメタ社によるCrusoe CPUでx86コードからCrusoeのVLIW命令への変換に用いられている。
適応的コンパイル技術はDEC社によるFX!32技術でも用いられていた。
Microsoft社による.NETプラットフォームも当初からJITによる実行を前提に設計されている。
Symantec社によるsymjitおよびBorland社によるJITコンパイラは初期の主要なJITコンパイラであった。
Sun Microsystems自身によるHotSpotコンパイラは本格的に適応的コンパイル方式を採用したJIT処理系である。
Hotspot以降はJITコンパイラ部分のインターフェースが規定されており、
JITコンパイルエンジン部分を差し替えることができるようになった。
IBMによるIBM JDK、BEAによるJRockitはいずれも適応的コンパイルを行う独自のJIT処理系を持っている。後者は特にx86に特化して実行効率を高めている。
学術的なものとしては、首藤氏によるShuJITや、富士通研と東工大によるリフレクション機能を扱うOpenJITなどがある。
インタプリタ方式との比較
適応的コンパイル(Adaptive Compilation)
JITコンパイル方式の利点
応用
JavaのJITコンパイラ