第468回:JITコンパイラとは

大和 哲
1968年生まれ東京都出身。88年8月、Oh!X(日本ソフトバンク)にて「我 ら電脳遊戯民」を執筆。以来、パソコン誌にて初歩のプログラミング、HTML、CGI、インターネットプロトコルなどの解説記事、インターネット関連の Q&A、ゲーム分析記事などを書く。兼業テクニカルライター。ホームページはこちら
(イラスト : 高橋哲史)


 「JITコンパイラ」とは、プログラムを実行する前に、その機器で実行できる形式に変換する仕組みのことです。

 JITコンパイラでプログラムを実行する際、中間言語(機械が解釈できる“機械語”と人間が読み書きできるソース言語の中間状態の言語)やソース言語(人間が読み書きできる状態のプログラム言語)で書かれたプログラムを、コンピュータが全て翻訳(変換)します。

 中間言語やソース言語は、そのままではコンピュータは処理できません。いわば“コンピュータで直接実行できない形式で書かれたプログラム”と言えます。コンピュータで実行するには、なんらかの形でそれを実行できる形に変換したりできるよう処理する必要があります。

 中間言語やソース言語を、コンピュータが実行できる形に変換する仕組みの1つが「コンパイラ」です。今回紹介する「JITコンパイラ」は、このコンパイラの一種です。「JIT」とは、「その都度」を意味する英語「Just In Time」の略で、都度変換する方式のことをジャストインタイム方式と呼びます。

 よく知られている、JITコンパイラとしては、たとえばサン・マイクロシステムズが、サーバーやデスクトップパソコン用に提供している「HotSpot」というJava仮想計算機(Vitual Machine、VM)があります。このJava VMでは、“Javaバイトコード”という中間形式で書かれたプログラムを、そのサーバーのネイティブ形式(そのままコンピュータで実行できる形式)に、ジャストインタイム方式で変換します。

 携帯電話では、2010年5月に発表されたスマートフォン用OS「Android 2.2」が、このJITコンパイラを搭載しています。

 Androidには、Dalvikと呼ばれるDex形式のプログラムを実行するための仮想計算機が搭載されており、Dalvikがアプリケーションを実行可能なネイティブ形式に変換して実行するのですが、Android 2.2に搭載されたDalvikでは、逐次実行ではなくジャストインタイム方式をサポートするようになりました。このため、Android 2.2ではそれ以前のバージョンと比べて、同じアプリケーションを実行した場合、実行速度が2~5倍程度、高速になるとされています。

JITコンパイラのメリットは、アプリ実行の高速化

 JITコンパイラのメリットは、端末のアーキテクチャー(規格)に依存しない、中間言語形式のプログラムを利用できるうえに、逐次実行では不可能だったアプリケーションの高速実行が可能なことが挙げられます。

 コンピュータ上でプログラムを最も速く実行できるプログラムの形式は、実行可能な“バイナリ”と呼ばれるデータです。何の加工や工夫もせずにそのままメモリに読み込み、CPUも余分な作業をせずに100%の力をプログラム実行に使うことができます。

 しかし、バイナリをそのままアプリとして流通させることにはいくつか問題があります。最も大きな問題は、互換性です。コンピュータのアーキテクチャーが少しでも変わってしまった場合、CPUがプログラムを解釈できなくなったり、あるいは誤動作してしまうことになります。

 そのため、アーキテクチャーが異なるCPUやハードウェア上でも同じプログラムを実行できるように、現在のコンピュータではさまざまな仕掛けが用意されています。

 たとえば、「一度プログラムを作ればどのマシンでも実行できる(Write once, run anywhere)」というコンセプトを標榜するJavaの場合、プログラムはJavaバイトコードという中間言語で流通させ、プログラムを実行させる環境としてVM(仮想計算機)が用意されています。

 初期のJava VM、あるいは現在の携帯電話用のJava VMの多くは、Javaバイトコードを解釈しながら実行します。つまり、「VM」というプログラムは「Javaバイトコードで書かれた命令を読む」→「解釈して実行」→「次の命令を読む」→「解釈して実行」という流れを繰り返しています。この方式は、実装が簡単で済むというメリットがありますが、その反面、1つ1つの命令を実行するたび、解釈のための時間が必要となります。これは、同じ命令を繰り返して実行するような“ループ”(これはコンピュータプログラムではかなり多用されています)がある場合、大きく時間を費やしてしまうことになります。

 そのため、解釈しながら実行するのではなく、ジャストインタイム方式で変換してからプログラムを実行するようにすると、全体的な処理が高速化できるのです。

 また、中間言語で書かれたプログラムが非効率なものであった場合、コンパイラであればネイティブコードに変換する際に、コードを効率よく実行できるように変換(これを「最適化」と呼ぶ)することも可能なので、中間言語の仕様とJITコンパイラの作り方によっては、さらに高速化することも可能です。

 実際、Javaの場合は、ソースプログラム(人間が解釈できるような、プログラムのコード)から中間形式であるJavaコードに変換する際にはほとんど最適化が行われず、JITコンパイラが最適化によって実行が一段と高速化されるケースがよく見受けられます。

 ただ、逆に言えば、ジャストインタイム方式ではプログラムを実行する前に一度プログラムを全てネイティブコードに変換する作業が入ることになります。そのため、この方式を採用した場合、プログラムサイズの大きさによっては、起動までに時間がかかってしまうこともある、というデメリットがあります。

 また、JITコンパイルを行う場合、端末上には中間言語で書かれたプログラムの他に、実行するために変換したネイティブコードを展開する必要があるため、逐次実行の場合に比べてメモリが多く必要になるというデメリットもあります。これは、これまで携帯電話や組み込みコンピュータといったリソースの少ないコンピュータではJITがあまり採用されなかった理由の1つでしょう。

 



(大和 哲)

2010/5/25 12:15