1. ホーム
  2. compilation

ジャストインタイムコンパイルとアヘッドオブタイムコンパイルの長所は何ですか?

2023-08-21 17:52:49

質問

最近考えているのですが、ほとんどの利点が JIT コンパイルに与えられた利点のほとんどは、多かれ少なかれ、代わりに中間フォーマットに帰せられるべきであり、JIT それ自体はコードを生成するためのあまり良い方法ではないような気がします。

というわけで、これらは主に プロJIT のコンパイルに関する議論です。

  1. ジャストインタイムコンパイルは、より大きな移植性を可能にします。 それは中間フォーマットに起因しているのでは?つまり、いったんマシンに取り込んだ仮想バイトコードをネイティブバイトコードにコンパイルすることを妨げるものは何もないのです。移植性は「配布」段階の問題であり、「実行」段階での問題ではありません。
  2. なるほど、では実行時にコードを生成することについてはどうでしょうか? まあ、同じことが当てはまります。本当のジャストインタイム ニーズのためのジャストインタイム コンパイラーを、ネイティブ プログラムに統合することを妨げるものは何もありません。
  3. しかし、ランタイムはとにかく一度だけネイティブ コードにコンパイルし、結果の実行ファイルをハードドライブのどこかのキャッシュに保存します。 ええ、もちろんです。しかし、それは時間の制約の下であなたのプログラムを最適化したのであって、そこから先が良くなるわけではありません。次の段落を参照してください。

とは違うのです。 先行 のコンパイルにも利点がなかったわけではありません。 ジャストインタイム コンパイルには時間の制約があります。プログラムが起動する間、エンドユーザーをずっと待たせておくわけにはいかないので、どこかでトレードオフを行う必要があるのです。たいていの場合、最適化の度合いを減らすだけです。私の友人は プロファイリングの証拠 関数をインライン化し、ループを手動で展開する (その過程でソース コードを難読化する) ことで、パフォーマンスにプラスの影響があったというプロファイリングの証拠があります。 C# 数値計算プログラムにおいて、パフォーマンスに良い影響を与えました。 C で同じことをしても、良い結果は得られませんでした。これは、私のコンパイラに許された広範な変換によるものだと思います。

それなのに、私たちはジットプログラムに囲まれているのです。 C# Java はどこにでもありますし、Pythonのスクリプトはある種のバイトコードにコンパイルできますし、他のプログラミング言語の束も同じだと思います。私が見逃している正当な理由があるはずです。では、なぜ ジャストインタイム のコンパイルが アヘッドオブタイム コンパイルに優れているのでしょうか?


EDIT いくつかの混乱を解消するために、私が実行ファイルの中間表現に賛成であることを述べるのは重要かもしれません。これには多くの利点があります (そして実際、のほとんどの議論は、を使用することです)。 ジャストインタイム に対するほとんどの議論が、実は中間表現に対する議論なのです)。私の質問は、それらがどのようにネイティブ コードにコンパイルされるべきかについてです。

ほとんどのランタイム(またはそのためのコンパイラ)は、ジャストインタイムまたはアヘッドオブタイムのいずれかをコンパイルすることを好むでしょう。例えば 先読み のコンパイルは、コンパイラが最適化を実行する時間が長いので、私にとってはより良い選択肢に見えますが、なぜ Microsoft や Sun、その他すべての人がその逆を行くのかが不思議です。私は、プロファイリング関連の最適化については、私の経験では ジャストインタイム というのも、私の経験では、コンパイルされたプログラムは貧弱な基本的最適化を表示していたからです。

の例が必要だったので、C言語のコードを使った例を使いました。 先読み コンパイルと ジャストインタイム のコンパイルと比較します。という事実は C のコードが中間表現に出力されなかったことは、この状況とは無関係です。 先読み コンパイルがより良い結果を即座にもたらすことができることを示す必要がありました。

どのように解決するのですか?

この ngenツールページ を参照してください (あるいは、少なくともネイティブ イメージと JIT コンパイルされたイメージの良い比較を提供しています)。事前にコンパイルされた実行可能ファイルには、通常、次のような利点があります。

  1. ネイティブ画像は、起動アクティビティがあまりなく、少ないメモリ (JIT コンパイラが必要とするメモリ) の静的な量を必要とするため、ロードが速くなります。
  2. ネイティブ イメージはライブラリ コードを共有できますが、JIT コンパイルされたイメージは共有できません。

ジャストインタイム コンパイルされた実行可能ファイルは、通常これらのケースで優位に立ちます。

  1. ネイティブ イメージは、バイトコード対応物よりも大きい。
  2. 元のアセンブリまたはその依存関係の 1 つが変更されるたびに、ネイティブ イメージを再生成する必要があります。

コンポーネントの 1 つが変更されるたびに、先行してコンパイルされている画像を再生成する必要があるのは 巨大 であり、ネイティブ イメージにとって不利です。一方、JIT コンパイルされたイメージはライブラリ コードを共有できないため、深刻なメモリ ヒットを引き起こす可能性があります。オペレーティング システムは、任意のネイティブ ライブラリを 1 つの物理的な場所にロードし、その不変部分を、それを使用したいすべてのプロセスで共有することができるため、特にほぼすべてのプログラムが使用するシステム フレームワークでは、大幅なメモリ節約につながります。(これは、JIT コンパイルされたプログラムが実際に使用するものだけをコンパイルするという事実によって、いくらか相殺されると想像しています)。

この問題に関するマイクロソフトの一般的な考察は、大規模なアプリケーションは一般的に先行してコンパイルされることで利益を得ますが、小規模なものは一般的に利益を得ません、ということです。