ジャストインタイムコンパイル

ウィキペディアから、無料の百科事典
ナビゲーションにジャンプ 検索にジャンプ

コンピューティングでは、ジャストインタイムJITコンパイル動的変換またはランタイムコンパイルも)[1]は、実行前ではなく、プログラムの実行中(実行時)にコンパイルを伴うコンピューターコードを実行する方法です。[2]これはソースコードの変換で構成されている場合がありますが、より一般的にはマシンコードへのバイトコード変換です、その後直接実行されます。 JITコンパイラを実装するシステムは、通常、実行中のコードを継続的に分析し、コンパイルまたは再コンパイルによって得られるスピードアップがそのコードのコンパイルのオーバーヘッドを上回るコードの部分を識別します。

JITコンパイルは、マシンコードへの変換に対する2つの従来のアプローチ(事前コンパイル(AOT)と解釈)を組み合わせたものであり、両方の長所と短所を組み合わせたものです。[2]大まかに言って、JITコンパイルは、コンパイルされたコードの速度と解釈の柔軟性を組み合わせ、インタプリタのオーバーヘッドと、(解釈だけでなく)コンパイルとリンクの追加のオーバーヘッドをもたらします。 JITコンパイルは動的コンパイルの形式であり、動的再コンパイルマイクロアーキテクチャ固有の高速化などの適応最適化を可能にします。 [nb 1] [3]ランタイムシステムは遅延バインドされたデータ型を処理し、セキュリティ保証を適用 できるため、解釈とJITコンパイルは動的プログラミング言語に特に適しています。

歴史

最も初期に公開されたJITコンパイラは、一般に1960年ジョンマッカーシーによってLISPで動作するされています。コンパイラの出力をパンチカードに保存する必要があります[5] (ただし、これは「コンパイルアンドゴーシステム」としてより正確に知られています)。もう1つの初期の例は、1968年に正規表現の最初のアプリケーションの1つを提供したKen Thompsonによるもので、ここではテキストエディタQEDでのパターンマッチングに使用されました。[6]速度を上げるために、Thompsonは、互換性のあるタイムシェアリングシステムでIBM7094コードにJITすることで正規表現のマッチングを実装しました[4]コンパイルされたコードを解釈から導き出すための影響力のある手法は、1970年にJames G. Mitchellによって開拓され、実験言語LC²に実装されました。[7] [8]

Smalltalk(c。1983)は、JITコンパイルの新しい側面を開拓しました。たとえば、マシンコードへの変換はオンデマンドで実行され、結果は後で使用するためにキャッシュされました。メモリが不足すると、システムはこのコードの一部を削除し、再度必要になったときに再生成します。[2] [9] SunのSelf言語はこれらの技術を大幅に改善し、かつては世界最速のSmalltalkシステムでした。最適化されたC [10]の最大半分の速度を達成しますが、完全にオブジェクト指向の言語を使用します。

自己はSunに見捨てられましたが、調査はJava言語になりました。「ジャストインタイムコンパイル」という用語は、製造用語「ジャストインタイム」から借用され、Javaによって普及し、JamesGoslingは1993年の用語を使用しています。[11]現在、JITingはJava仮想マシンのほとんどの実装で使用されています。 、HotSpotがこの研究ベースを構築し、広く使用しているため。

HPプロジェクトDynamoは、「バイトコード」形式とマシンコード形式が同じである実験的なJITコンパイラでした。システムはPA-6000マシンコードをPA-8000マシンコードに変換しました。[12]直感に反して、これにより、マシンコードレベルで最適化が可能になったため、場合によっては30%のスピードアップが実現しました。たとえば、キャッシュの使用を改善するためのコードのインライン化や、ダイナミックライブラリや他の多くのランタイムへの呼び出しの最適化が可能になりました。従来のコンパイラでは試行できない最適化。[13] [14]

2020年11月、 PHP8.0はJITコンパイラーを導入しました。[15]

デザイン

バイトコードでコンパイルされたシステムでは、ソースコードはバイトコードと呼ばれる中間表現に変換されます。バイトコードは特定のコンピューターのマシンコードではなく、コンピューターアーキテクチャ間で移植可能である可能性があります。次に、バイトコードは仮想マシンによって解釈されるか、仮想マシン上で実行されます。 JITコンパイラは、多くのセクション(または完全にまれに)のバイトコードを読み取り、プログラムをより高速に実行できるように、それらを動的にマシンコードにコンパイルします。これは、ファイルごと、関数ごと、または任意のコードフラグメントに対しても実行できます。コードは、実行されようとしているときにコンパイルでき(したがって、「ジャストインタイム」という名前が付けられます)、再コンパイルすることなく、後でキャッシュして再利用できます。

対照的に、従来のインタープリターされた仮想マシンは、バイトコードを単純に解釈しますが、一般的にパフォーマンスははるかに低くなります。一部のインタプリタは、最初にバイトコードにコンパイルするステップなしでソースコードを解釈することさえあり、パフォーマンスはさらに低下します。静的にコンパイルされたコードまたはネイティブコードは、デプロイ前にコンパイルされます。動的コンパイル環境は、実行中にコンパイラーを使用できる環境です。 JIT手法を使用する一般的な目標は、静的コンパイルのパフォーマンスに到達するか、それを超えることです。、バイトコード解釈の利点を維持しながら:元のソースコードを解析して基本的な最適化を実行する「手間のかかる作業」の多くは、展開前のコンパイル時に処理されることがよくあります。バイトコードからマシンコードへのコンパイルは、ソースからのコンパイルよりもはるかに高速です。 。デプロイされたバイトコードは、ネイティブコードとは異なり、移植可能です。ランタイムは、解釈されたバイトコードのようにコンパイルを制御できるため、安全なサンドボックスで実行できます。ポータブルバイトコードコンパイラはすでに多くの作業を行っているため、バイトコードからマシンコードまでのコンパイラは記述が簡単です。

JITコードは通常、インタープリターよりもはるかに優れたパフォーマンスを提供します。さらに、多くの最適化は実行時にのみ実行可能であるため、静的コンパイルよりも優れたパフォーマンスを提供できる場合があります。[16] [17]

  1. コンパイルは、対象のCPUとアプリケーションが実行されるオペレーティングシステムモデルに合わせて最適化できます。たとえば、JITは、 CPUがSSE2ベクトルCPU命令をサポートしていることを検出すると、それらを選択できます。静的コンパイラでこのレベルの最適化の特異性を得るには、目的のプラットフォーム/アーキテクチャごとにバイナリをコンパイルするか、単一のバイナリ内にコードの一部の複数のバージョンを含める必要があります。
  2. システムは、プログラムが置かれている環境でプログラムが実際にどのように実行されているかに関する統計を収集でき、最適なパフォーマンスを得るために再配置および再コンパイルできます。ただし、一部の静的コンパイラーは、プロファイル情報を入力として受け取ることもできます。
  3. システムは、動的リンクの利点を失うことなく、また静的コンパイラーとリンカーに固有のオーバーヘッドなしに、グローバルなコード最適化(ライブラリー関数のインライン化など)を実行できます。具体的には、グローバルインライン置換を行う場合、静的コンパイルプロセスで実行時チェックが必要になる場合があり、オブジェクトの実際のクラスがインラインメソッドをオーバーライドした場合に仮想呼び出しが発生することを確認し、配列アクセスの境界条件チェックを処理する必要がある場合があります。ループ内。多くの場合、ジャストインタイムコンパイルを使用すると、この処理をループから外すことができ、多くの場合、速度が大幅に向上します。
  4. これは静的にコンパイルされたガベージコレクションされた言語で可能ですが、バイトコードシステムは、実行されたコードをより簡単に再配置して、キャッシュの使用率を高めることができます。

JITは実行時にネイティブバイナリイメージをレンダリングして実行する必要があるため、真のマシンコードJITには、実行時にデータを実行できるプラットフォームが必要であり、ハーバードアーキテクチャベースのマシンでそのようなJITを使用することは不可能です。特定のオペレーティングシステムや仮想マシンについても同じことが言えます。ただし、特殊なタイプの「JIT」は、物理マシンのCPUアーキテクチャを対象としない可能性がありますが、生のマシンコードの制限が優先される、特にそのバイトコードのVMが最終的にJITをネイティブコードに利用する場合は、最適化されたVMバイトコードを対象とします。[18]

パフォーマンス

JITは、バイトコードのロードとコンパイルに時間がかかるため、アプリケーションの初期実行にわずかから顕著な遅延を引き起こします。この遅延は、「起動時間遅延」または「ウォームアップ時間」と呼ばれることもあります。一般に、JITが実行する最適化が多いほど、生成されるコードは優れていますが、初期遅延も増加します。したがって、JITコンパイラは、コンパイル時間と生成したいコードの品質との間でトレードオフを行う必要があります。起動時間には、JITコンパイルに加えて、IOバウンド操作の増加を含めることができます。たとえば、Java仮想マシン(JVM)のrt.jarクラスデータファイルは40 MBであり、JVMはこのコンテキスト的に巨大なファイルで大量のデータを探す必要があります。 [19]

SunのHotSpotJava仮想マシンで使用される可能な最適化の1つは、解釈とJITコンパイルを組み合わせることです。アプリケーションコードは最初に解釈されますが、JVMはバイトコードのどのシーケンスを監視します頻繁に実行され、ハードウェアで直接実行するためにそれらをマシンコードに変換します。数回しか実行されないバイトコードの場合、これによりコンパイル時間が節約され、初期レイテンシが短縮されます。頻繁に実行されるバイトコードの場合、JITコンパイルは、遅い解釈の初期段階の後、高速で実行するために使用されます。さらに、プログラムはそのコードの少数を実行するのにほとんどの時間を費やすので、コンパイル時間の短縮は重要です。最後に、最初のコード解釈中に、コンパイル前に実行統計を収集できます。これは、より適切な最適化を実行するのに役立ちます。[20]

正しいトレードオフは、状況によって異なる場合があります。たとえば、SunのJava仮想マシンには、クライアントとサーバーの2つの主要なモードがあります。クライアントモードでは、起動時間を短縮するために、最小限のコンパイルと最適化が実行されます。サーバーモードでは、起動時間を犠牲にしてアプリケーションの実行後にパフォーマンスを最大化するために、広範なコンパイルと最適化が実行されます。他のJavaジャストインタイムコンパイラは、メソッドが実行された回数の実行時測定値と、メソッドのバイトコードサイズを組み合わせて、いつコンパイルするかを決定するヒューリスティックとして使用していました。[21] さらに別の方法では、実行された回数をループの検出と組み合わせて使用​​します。[22]一般に、実行時間の長いアプリケーションよりも実行時間の短いアプリケーションで最適化する方法を正確に予測することははるかに困難です。[23]

Microsoftのネイティブイメージジェネレーター(Ngen)は、初期遅延を減らすためのもう1つのアプローチです。[24] Ngenは、共通中間言語イメージのバイトコードをマシンネイティブコードにプリコンパイル(または「プリJIT」)します。その結果、実行時のコンパイルは必要ありません。Visual Studio2005に同梱されている.NETFramework 2.0は、インストール直後にすべてのMicrosoftライブラリDLLでNgenを実行します。プレジッティングは、起動時間を改善する方法を提供します。ただし、プロファイルに基づく最適化を行わずにコードを静的にコンパイルするのと同じ理由で、生成されるコードの品質はJITされたものほど良くない場合があります。、極端な場合、JITでコンパイルされたコードほど良くなることはできません。たとえば、インラインキャッシングを駆動するためのプロファイリングデータが不足しています。[25]

AOT(事前)コンパイラーをJITコンパイラー(Excelsior JET)またはインタープリター(GNUコンパイラーfor Java )と組み合わせたJava実装も存在します

セキュリティ

JITコンパイルは基本的に実行可能データを使用するため、セキュリティ上の課題と悪用の可能性があります。

JITコンパイルの実装は、ソースコードまたはバイトコードをマシンコードにコンパイルして実行することで構成されます。これは通常、メモリ内で直接実行されます。JITコンパイラは、通常の事前コンパイルのように、マシンコードをディスクに出力してから別のプログラムとして呼び出すのではなく、マシンコードをメモリに直接出力してすぐに実行します。最新のアーキテクチャでは、実行可能スペースの保護が原因でこれが問題になります。任意のメモリを実行できません。そうしないと、潜在的なセキュリティホールが発生します。したがって、メモリは実行可能としてマークする必要があります。セキュリティ上の理由から、書き込み可能/実行可能メモリはセキュリティホールであるため、これはコードがメモリに書き込まれ、読み取り専用とマークされた後に実行する必要があります( W ^ Xを参照)。[26]たとえば、FirefoxのJavascript用JITコンパイラは、Firefox46のリリースバージョンでこの保護を導入しました。[27]

JITスプレーは、ヒープスプレーにJITコンパイルを使用するコンピューターセキュリティエクスプロイトのクラスです。結果のメモリは実行可能になり、実行をヒープに移動できる場合はエクスプロイトが可能になります。

を使用します

JITコンパイルは、一部のプログラムに適用することも、特定の容量、特に正規表現などの動的容量に使用することもできますたとえば、テキストエディタは、実行時に提供される正規表現をマシンコードにコンパイルして、より高速なマッチングを可能にする場合があります。パターンは実行時にのみ提供されるため、これを事前に実行することはできません。いくつかの最新のランタイム環境は、 Microsoft.NETとともに、 Javaのほとんどの実装を含む、高速コード実行のためにJITコンパイルに依存しています。。同様に、多くの正規表現ライブラリは、バイトコードまたはマシンコードのいずれかに正規表現をJITコンパイルする機能を備えています。 JITコンパイルは、マシンコードをあるCPUアーキテクチャから別のCPUアーキテクチャに変換するために、一部のエミュレータでも使用されます。

JITコンパイルの一般的な実装は、最初にバイトコードへのAOTコンパイル(仮想マシンコード)(バイトコードコンパイルと呼ばれる)を行い、次にバイトコードの解釈ではなく、マシンコードへのJITコンパイル(動的コンパイル)を行うことです。これにより、コンパイルによる遅延が発生しますが、解釈と比較して実行時のパフォーマンスが向上します。JITコンパイラーは、インタープリターと同様に継続的に変換しますが、コンパイルされたコードをキャッシュすると、特定の実行中の同じコードの将来の実行の遅延が最小限に抑えられます。プログラムの一部のみがコンパイルされるため、実行前にプログラム全体がコンパイルされた場合よりも大幅に遅延が少なくなります。

も参照してください

メモ

  1. ^ Ahead-of-Timeコンパイラは、特定のマイクロアーキテクチャをターゲットにすることもできますが、その点でAOTとJITの違いは移植性の1つです。JITは、実行時に現在実行中のCPUに合わせてコードをレンダリングできますが、AOTは、一般化されたuarchesのサブセットを最適化する代わりに、ターゲットCPUを事前に知っている必要があります。完全に不安定な場合があります。

参考文献

  1. ^ 言語、コンパイラ、およびランタイムシステム、ミシガン大学、コンピュータサイエンスおよびエンジニアリング、 2018年3月15日取得
  2. ^ a b c Aycock2003
  3. ^ 「JITは私のCPUを利用していますか?」デビッドノタリオのウェブログ2018年12月3日取得
  4. ^ a b Aycock 2003、2。JITコンパイル手法、2.1ジェネシス、p。98。
  5. ^ McCarthy、J。(1960年4月)。「S式の再帰関数とその機械による計算、パートI」。ACMの通信3(4):184–195。CiteSeerX10.1.1.111.8833_ 土井10.1145 /367177.367199S2CID1489409_  
  6. ^ トンプソン1968
  7. ^ Aycock 2003、2。JITコンパイル手法、2.2LC²、p。98〜99。
  8. ^ ミッチェル、JG(1970)。「柔軟で効率的なインタラクティブプログラミングシステムの設計と構築」。 {{cite journal}}引用ジャーナルには|journal=ヘルプ)が必要です
  9. ^ Deutsch、LP; シフマン、AM(1984)。「Smalltalk-80システムの効率的な実装」(PDF)POPL '84:プログラミング言語の原則に関する第11回ACM SIGACT-SIGPLANシンポジウムの議事録:297–302土井10.1145 /800017.800542ISBN  0-89791-125-3S2CID3045432 _ 2004年6月18日にオリジナル (PDF)からアーカイブされました
  10. ^ 「アーカイブされたコピー」research.sun.com2006年11月24日にオリジナルからアーカイブされました2022年1月15日取得{{cite web}}:CS1 maint:タイトルとしてアーカイブされたコピー(リンク
  11. ^ Aycock 2003、2.14 Java、p。107、脚注13。
  12. ^ 「Dynamo:透過的な動的最適化システム」。Vasanth Bala、Evelyn Duesterwald、Sanjeev Banerjia PLDI'00プログラミング言語の設計と実装に関するACMSIGPLAN2000会議の議事録。1〜12ページ。DOI10.1145/ 349299.349303。2012年3月28日取得
  13. ^ ジョンJannotti。「HPのダイナモ」ArsTechnica 2013年7月5日取得
  14. ^ 「HPDynamoプロジェクト」2002年10月19日にオリジナルからアーカイブされました2016年4月12日取得{{cite web}}:CS1 maint:不適切なURL(リンク
  15. ^ 桐、リアム(2020年11月27日)。「プログラミング言語PHP8がリリースされました:この新しいJITコンパイラはパフォーマンスの向上を示しています」ZDNet2020年11月28日取得
  16. ^ クローチェ、ルイ。「ジャストインタイムコンパイル」(PDF)コロンビア大学2018-05-03にオリジナル(PDF)からアーカイブされました。
  17. ^ 「JITとAOTコンパイルの利点は何ですか」スタックオーバーフロー2010年1月21日。
  18. ^ 「JITベースの言語をWebassemblyにコンパイルする」スタックオーバーフロー2018年12月4日取得
  19. ^ Haase、Chet(2007年5月)。「コンシューマーJRE:リーナー、ミーナーJavaテクノロジー」サンマイクロシステムズ2007年7月27日取得
  20. ^ 「JavaHotSpotパフォーマンスエンジンアーキテクチャ」Oracle.com 2013年7月5日取得
  21. ^ Schilling、Jonathan L.(2003年2月)。「最も単純なヒューリスティックは、Java JITコンパイラーで最高かもしれません」(PDF)SIGPLANの通知38(2):36–46。土井10.1145 /772970.772975S2CID15117148_ 2015年9月24日にオリジナル(PDF)からアーカイブされました  
  22. ^ 菅沼敏夫、安江敏明、川仁元弘、小松英明、中谷敏夫、「Javaジャストインタイムコンパイラの動的最適化フレームワーク」、オブジェクト指向プログラミング、システム、言語、およびアプリケーション(OOPSLA '01)、pp。180–195、2001年10月14–18日。
  23. ^ Matthew Arnold、Michael Hind、Barbara G. Ryder、「選択的最適化の実証的研究」、第13回並列コンピューティングのための言語とコンパイラに関する国際ワークショップの議事録-改訂論文、pp。49–67、2000年8月10–12日。
  24. ^ 「ネイティブイメージジェネレーター(Ngen.exe)」Msdn2.microsoft.com 2013年7月5日取得
  25. ^ Matthew R. Arnold、Stephen Fink、David P. Grove、Michael Hind、およびPeter F. Sweeney、「仮想マシンにおける適応最適化の調査、IEEEの議事録、92(2)、2005年2月、449ページ–466。
  26. ^ 「JITの方法–はじめに」、Eli Bendersky、2013年11月5日午前5時59分
  27. ^ De Mooij、1月。 「Firefoxで有効なW ^ XJITコード」Jan DeMooij 2016年5月11日取得

さらに読む

外部リンク