実行時コンパイラ
プログラムの実行 |
---|
一般的な概念 |
コードの種類 |
コンパイル戦略 |
有名なランタイム |
|
有名なコンパイラとツールチェーン |
|
実行時コンパイラ(じっこうじコンパイラ、just-in-time compiler、JITコンパイラ)とは、ソフトウェアの実行時にソースコードをコンパイルするコンパイラのこと。通常のコンパイラはコンパイルを実行前に事前に行い、これをJITと対比して事前コンパイラ (ahead-of-timeコンパイラ、AOTコンパイラ)と呼ぶ。
概要
[編集]ソフトウェアを構成するモジュール、クラス、関数などのある単位のコードがまさに実行されるその時に、コンパイルすることから「Just In Time」と名付けられた。動的コンパイルという用語は、実行時に機械語を生成するというより広い意味であり、JITコンパイルは動的コンパイルの一種である。
JIT方式の主な利点は、オペレーティングシステムやCPUに依存しないソースコードや中間コードでソフトウェアを配布できる事である。これはその都度コードを解釈しながら実行する解釈実行方式でも可能であるが、JITではコンパイルを行いメモリ上に生成した機械語が実行されるため、実行速度を向上させることができる。
事前コンパイルと比べ、JITではコンパイル時間がプログラム実行時間のオーバーヘッドとなる。また、事前コンパイルで可能な高度で時間のかかる最適化を行えないといった欠点がある。
利点
[編集]上記以外にもJITコンパイルは実行環境を知った上でそれに応じた生成コードの選択や最適化が可能という利点もある。
一例として、インテルのx86 CPUの場合、IA-32アーキテクチャの範囲内でCPU世代毎に命令が拡張されてきたが、アプリケーションの後方互換性を保持しようとすると、80386と互換の命令しか使うことができない。例えば、MMX PentiumのMMX命令は80386やPentiumでは実行できない。JIT方式ではCPUがMMXをサポートしているならMMX命令を使ったコードを生成し、そうでなければ多少効率の悪いPentiumの命令範囲内で実行する、ということができる。
また、実行環境のキャッシュやメモリのサイズ、速度特性などは実行時にならないとわからないが、JITコンパイルでは実行中のCPUやメモリの情報を知ることができる。このためそれに応じたコードを生成し、事前コンパイルよりも優れたコードを生成できる可能性がある。
さらに、オブジェクト指向言語では仮想メソッドの呼び出しは仮想関数表を経由した間接呼び出しになるが、動的コンパイルでは、そのメソッドをオーバーライド定義したサブクラスが存在しない限り、間接呼び出しを静的束縛として呼び出したり、インライン展開することができる(そのメソッドをオーバーライドするサブクラスが動的にロードされる可能性があるが、その場合はこのコンパイルされたメソッドは最適化戻し (deoptimize) される必要がある)。
適応的コンパイル (Adaptive Compilation)
[編集]上記のJITコンパイラの短所を補う一方式として適応的コンパイルがある。これは、起動当初はインタプリタとして実行し、繰り返し実行されるコードを検出(プロファイリング)、その部分のみをコンパイルするというものである。コードが使われた時にすぐにコンパイルするのではなく、何回か呼ばれた後に遅らせてコンパイルすることを遅延コンパイル (Lazy Compilation)と呼ぶ。
プログラム実行時間の大半はごく一部のコードに費やされるという経験則がある - 典型的に実行時間の80%は20%のコードに費やされる、80-20の法則。適応的コンパイルはこのようなコードのみをコンパイルすることで、起動時のオーバーヘッドや利用メモリ増大を抑えつつ、実行速度を向上することができる。この適応的最適化 (Adaptive Optimization) は、静的コンパイルでは得られない情報を元に最適化するため、むしろパフォーマンスが上がる場合もある。
数百件以内といった少量レコードを処理するバッチジョブが、一日に何百本、何千本も走る場合は注意が必要である。JITコンパイルを用いた場合、適応的コンパイルをしてさえも、ジョブの初めに共通的なクラスのコンパイル処理が何百回と行われる。処理件数が少ないので、クラス群の多くはコンパイル効果が出る前に、あるいはコンパイルさえされないうちにジョブが終わってしまう。その結果、ユーザロジックよりこうしたオーバヘッドにCPUなどの資源が消費されてしまう。処理件数によってJIT/AOTの有利不利が変わるが、使い分けるのは難しい。
また、(Javaについていえば)AOTコンパイラを通常適用しにくい[独自研究?]。これらの理由で、性能面ではマイナスな場面でも一般的な[独自研究?]JITコンパイラを使用していることがある。長時間のバッチジョブおよびオンラインでは、JITコンパイラ、特に適応的コンパイルが概してフィットしている[独自研究?]。適応的コンパイルの最適化のために、何回実行されたらコンパイルするといったパラメタが用意されているものもある[要出典]。パラメタチューニングは万能ではないとしても重要である[独自研究?]。
応用
[編集]JITはJavaの普及に伴い広範囲に使われるようになったが、JavaのHotSpot技術はSelf言語の動的コンパイル技術研究に基づいている。それに先立つ商用SmalltalkでもJITコンパイル技術は確立されていた。
Crusoeでx86コードからCrusoe VLIW命令への変換にも用いられる。適応的コンパイルはDEC社によるFX!32でも用いられていた。
.NETプラットフォームも当初からJITを前提に設計されている。
JavaのJITコンパイラ
[編集]Symantec社のsymjitおよびBorland社のJITコンパイラは初期の主要なJITコンパイラであった。
Sun MicrosystemsのHotSpotコンパイラは本格的に適応的コンパイル方式を採用した。Hotspot以降はJITコンパイラ部分のインタフェースが規定されており、JITコンパイルエンジン部分を差し替えることが可能になった。
IBMのIBM JDK、BEAのJRockitはいずれも独自の適応的コンパイルを行う。後者は特にx86に特化して実行効率を高めている。
学術的分野では、首藤によるShuJITや、富士通研究所と東京工業大学によるリフレクション機能を扱うOpenJITなどがある。
JavaScriptのJITコンパイラ
[編集]近年の主要なウェブブラウザはJavaScriptのエンジンにJITコンパイラを搭載し、高速処理できるようになっている。
Internet Explorer 9、Mozilla Firefox 3.5、Google Chrome 1、Safari 4、Opera 10.50、Opera Mobile 10.1以降のウェブブラウザに搭載されている。NetFront Browser 4.1 には搭載されていない。
実行時に変数に代入された値の統計データから変数に型を割り振ることでJITコンパイルし、高速にJavaScriptを処理できるようになった[1]。Google ChromeのV8などでは、インタプリタを使わずに最初からJITコンパイルし、変数の型は実行時に随時割り振る。Firefox 3.5では事前に一度インタプリタで実行して、その情報から型を割り振りながらJITコンパイルするタイプがある。どちらのタイプであっても型が安定している場合は高速に実行できる。
関連項目
[編集]参照
[編集]外部リンク
[編集]- John Aycock, A brief history of just-in-time