私は最近、プラットフォームに依存しないコードをネイティブ コードにコンパイルするために JIT コンパイラが使用されていることを知りました。JVM と .net ランタイム環境はこれを使用して、パフォーマンスを向上させ、コンパイル時間を大幅に短縮します。私の質問は、ネイティブ コードに直接コンパイルする通常のコンパイラ (C コンパイラなど) も JIT として作成しないのはなぜですか? JITコンパイラの場合、使用上の制限や仕様はありますか?
4 に答える
JITにはメリットとデメリットがあります。JIT コンパイラは特定のプラットフォームごとにコードを最適化する方法を検出できるため、多くの異なる PC にソフトウェアを展開する場合、JIT は非常に役立ちます。
問題は、JIT によって、ソフトウェアを最初に実行する前に実行する必要がある別のステップが追加されることです。最初に IL にコンパイルし、次にマシン コードにコンパイルする必要があります。これは、余分なパフォーマンス オーバーヘッドを意味します。ただし、この IL からマシン コードへの変換は、ソフトウェアを初めて実行するときにのみ実行する必要があるため、その後の各呼び出しははるかに高速になります。
したがって、基本的に (経験則として)、次のように言えます。ソフトウェアが長時間実行されるプロセスである場合は、多くの場合、JIT を使用することをお勧めします。ソフトウェアの寿命が短い場合は、ネイティブ コードを使用することをお勧めします。
最新の JavaScript 実装も JIT を行います。一部の PHP、Python、および Ruby の実装も (少なくとも) 行います。ただし、JIT の秘訣は、それらが比較的最近開発されたものであることです。JIT が機能する理由の 1 つは、エンド ユーザー マシン上に存在する何らかのタイプのフレームワークまたはランタイムに依存しており、正しい処理を実行できることです。そのマシンとアプリケーションのインスタンスの最適化。
コンピューターの「ベアメタル」に近づけたい言語の場合、追加の抽象化レイヤーに依存することは必ずしも意味がありません。
私が考えることができるいくつかの理由があります:
プリコンパイルされたバイナリは、最高のパフォーマンスを達成するために数日かかる高レベルの最適化を使用できます。JIT コンパイラではそれは望ましくありません。
最初の JIT コンパイルは直接解釈よりも時間がかかる可能性があり、一般的なケースの後続の実行では違いが目立たない
JIT コンパイルは、他のランタイム プロセスに必要なユーザー リソースを占有する可能性があります (JIT でコンパイルされた 3D ゲームはあまり見ません)。
プリコンパイルされたインタープリターは、効率的に記述されていれば、パフォーマンスを低下させることなく、ユーザーがソースを即座に変更できるようにしながら、十分に近い速度を達成できます。
これは、x86 命令セットの分岐と、消費者向けデバイスでのアーム、ミップなどの使用の拡大、およびさまざまなオペレーティング システムにより、商用ソフトウェアで変化し始めています。ビデオ カードのネイティブ コードを使用する JIT コンパイラの機能 (これも大きく異なります) を追加すると、すべての固有の組み合わせに対して最適化されたコンパイル済みバージョンを配布しようとするのは、ますます合理的ではなくなります。ある時点で、gpu だけでなくすべての CPU にアクセスできる合理的な JIT コンパイラーは、(たとえば) x86 のサブセットに限定されたコンパイル済みの同等物よりも優れたパフォーマンスを発揮します。
よく聞かれることの 1 つは、バイトコードを配布できるかどうかということです... ほとんどですが、完全ではありません。Java は仮想的に設計されているため、libc が行うエンディアンやその他のハードウェアの問題、または各アーキテクチャのカスタム アセンブリ言語ビット (仮想マシンに実装されるすべてのもの) について心配する必要がないため、Java で機能します。 ) 本当に強力な基盤を得るには、JIT 用に設計された基本的な libc を実装する必要があります (コードが簡素化され、ライセンスが許可されているため、musl libc に基づいている可能性があります)。
ほとんどの C コンパイラ (GCC など) と同様に、事前にコンパイラを最適化すると、JIT コンパイラよりも優れたマシン コードが生成される場合があります。しかし、事前コンパイラーは通常、最適化に (JIT よりも) はるかに多くの時間を必要とします。たとえば、gcc -O3
ほとんどの JIT JVM では実行できない多くの広範な最適化を行っています。したがって、gcc -O3
多くの場合、非常に効率的なマシン コードが生成されます (JVM よりもはるかに優れています)。
ただし、場合によっては、JIT テクノロジの方が優れたコードを生成することがあります。これは、事前コンパイラが認識していないいくつかの動的プロパティを考慮に入れることができるためです。たとえば、JIT コンパイラは、ある特定の呼び出しサイトで、呼び出しの引数が通常 1 つの特定のクラスを持っていることを考慮することができます (そして、そのクラスは呼び出しサイトに依存し、動的に学習されます)。