77

私は最近それについて考えていました.JITコンパイルに与えられるほとんどの利点、多かれ少なかれ代わりに中間形式に起因するはずであり、ジッティング自体はコードを生成するための良い方法ではないようです.

したがって、これらは私がよく耳にする主なJITコンパイル支持の議論です。

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

事前コンパイルにも利点がなかったわけではありません。ジャストインタイムコンパイルには時間の制約があります。プログラムの起動中にエンド ユーザーを永遠に待たせることはできないため、どこかで実行するというトレードオフがあります。ほとんどの場合、最適化が少なくなります。私の友人は、関数のインライン展開とループの展開を "手動で" (処理中のソース コードを難読化する) ことで、C#数値処理プログラムのパフォーマンスにプラスの影響を与えたというプロファイリングの証拠を持っていました。私の側で同じことを行い、私のCプログラムが同じタスクを実行しても、肯定的な結果は得られませんでした。これは、私のコンパイラーが行うことを許可された広範な変換によるものだと思います。

それでも、私たちはジットされたプログラムに囲まれています。C#Javaはどこにでもあり、Python スクリプトはある種のバイトコードにコンパイルできます。他のプログラミング言語も同じように動作するはずです。私が行方不明になったのには、正当な理由があるに違いありません。では、ジャストインタイムコンパイルが事前コンパイルよりも優れている理由は何でしょうか?


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

ほとんどのランタイム (またはコンパイラー) は、ジャストインタイムまたは事前にコンパイルすることを好みます。コンパイラが最適化を実行するためにより多くの時間を割くことができるため、私には事前コンパイルの方が優れた代替手段のように思えますが、Microsoft、Sun、および他のすべての企業がなぜ逆の方向に進んでいるのか疑問に思っていますジャストインタイムでコンパイルされたプログラムでの私の経験では、基本的な最適化が貧弱であったため、プロファイリング関連の最適化については少し懐疑的です。

C コードの例を使用したのは、事前コンパイルとジャストインタイムコンパイルの例が必要だったからです。Cコードが中間表現に出力されなかったという事実は、状況とは関係ありません。なぜなら、事前にコンパイルした方がすぐにより良い結果が得られることを示す必要があったからです。

4

9 に答える 9

41
  1. 移植性の向上:成果物(バイトコード)の移植性を維持

  2. 同時に、よりプラットフォーム固有:JITコンパイルはコードが実行されるのと同じシステムで行われるため、その特定のシステムに対して非常に微調整することができます。事前コンパイルを行う場合(そしてそれでも同じパッケージをすべての人に出荷したい場合)、妥協する必要があります。

  3. コンパイラテクノロジの改善は、既存のプログラムに影響を与える可能性があります。より優れたCコンパイラは、すでに展開されているプログラムではまったく役に立ちません。より優れたJITコンパイラは、既存のプログラムのパフォーマンスを向上させます。10年前に作成したJavaコードは、今日ではより高速に実行されます。

  4. 実行時メトリックへの適応。JITコンパイラは、コードとターゲットシステムだけでなく、コードの使用方法も確認できます。実行中のコードをインストルメント化し、たとえば、メソッドパラメーターが通常持つ値に応じて最適化する方法を決定できます。

JITが起動コストを増加させるのは当然のことです。そのため、JITには時間の制約がありますが、事前コンパイルには必要なすべての時間がかかる可能性があります。これにより、起動時間がそれほど重要ではなく、コードが実際に高速になる前の「ウォームアップフェーズ」が許容されるサーバータイプのアプリケーションに適しています。

JITコンパイルの結果をどこかに保存して、次回再利用できるようになると思います。これにより、2回目のプログラム実行の「事前」コンパイルが可能になります。たぶん、SunとMicrosoftの賢い人々は、新しいJITはすでに十分であり、余分な複雑さは問題の価値がないという意見です。

于 2010-01-21T01:57:57.540 に答える
18

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

  1. ネイティブ イメージは、スタートアップ アクティビティがあまりなく、静的な量のメモリ (JIT コンパイラが必要とするメモリ) が少なくて済むため、読み込みが速くなります。
  2. ネイティブ イメージはライブラリ コードを共有できますが、JIT コンパイルされたイメージは共有できません。

通常、ジャストインタイムでコンパイルされた実行可能ファイルは、次のような場合に有利です。

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

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

この問題に関する Microsoft の一般的な考慮事項は、大規模なアプリケーションは通常、事前にコンパイルすることでメリットが得られるが、小規模なアプリケーションは一般的にそうではないということです。

于 2010-01-24T03:36:48.020 に答える
7

単純なロジックでは、バイトコードからでも巨大なMSOfficeサイズのプログラムをコンパイルすると時間がかかりすぎることがわかります。あなたは巨大な開始時間で終わるでしょう、そしてそれはあなたの製品から誰かを怖がらせるでしょう。もちろん、インストール中にプリコンパイルすることはできますが、これにも影響があります。

もう1つの理由は、アプリケーションのすべての部分が使用されるわけではないということです。JITは、ユーザーが気にする部分のみをコンパイルし、コードの80%をそのままにして、時間とメモリを節約します。

そして最後に、JITコンパイルは、通常のコンパイラーでは適用できない最適化を適用できます。仮想メソッドまたはメソッドの一部をトレースツリーでインライン化するようなものです。これは、理論的には、それらをより速くすることができます。

于 2010-01-21T01:59:23.353 に答える
5
  1. より良い反射サポート。これは、原則として事前コンパイルされたプログラムで実行できますが、実際にはほとんど発生しないようです。

  2. 多くの場合、プログラムを動的に観察することによってのみ理解できる最適化。たとえば、仮想関数のインライン化、スタック割り当てをヒープ割り当てに変換するためのエスケープ分析、およびロックの粗大化。

于 2010-01-21T02:00:06.880 に答える
4

多分それはプログラミングへの現代的なアプローチと関係があります. ご存知のように、何年も前に、プログラムを紙に書き、他の人がそれをパンチカードのスタックに変換してコンピューターに入力し、明日の朝、重量を量る紙のロールにクラッシュダンプを取得していました.半ポンド。コードの最初の行を書く前に、多くのことを考えなければなりませんでした。

そんな日々はとうの昔に過ぎ去りました。PHP や JavaScript などのスクリプト言語を使用すると、変更をすぐにテストできます。Java の場合はそうではありませんが、アプリサーバーはホット デプロイメントを提供します。したがって、バイトコード コンパイラは非常に単純なので、Java プログラムを高速にコンパイルできることは非常に便利です。

しかし、JIT 専用言語などというものはありません。かなり前から Java 用の事前コンパイラーが利用可能であり、最近では Mono がそれを CLR に導入しました。実際、Apple のアプリ ストアでは非ネイティブ アプリが禁止されているため、AOT コンパイルのおかげでMonoTouchはまったく可能です。

于 2010-01-21T05:57:49.623 に答える
2

ここにリストされていない JIT の利点の 1 つは、個別のアセンブリ/dll/jar をインライン化/最適化できることです (簡単にするために、ここからは「アセンブリ」を使用します)。

インストール後に変更される可能性のあるアセンブリ (プリインストールされたライブラリ、フレームワーク ライブラリ、プラグインなど) をアプリケーションが参照する場合、「インストール時にコンパイル」モデルでは、アセンブリの境界を越えてメソッドをインライン化することを控える必要があります。そうしないと、参照されているアセンブリが更新されたときに、システム上のアセンブリを参照しているインライン化されたコードをすべて見つけて、更新されたコードに置き換える必要があります。

JIT モデルでは、基になるコードが変更されていない 1 回の実行に対して有効なマシン コードを生成することのみを考慮するため、アセンブリ間で自由にインライン化できます。

于 2016-11-05T18:33:02.483 に答える
2

Google が Dalvik Virtual Machine (本質的に HotSpot のような別の Java Virtual Machine) を AOT コンパイラである Android Run Time (ART) に置き換える方向に進んでいるのを見たので、私もこれを理解しようとしましたが、Java は通常 HotSpot を使用します。 、JIT コンパイラです。どうやら、ARM は Dalvik よりも ~ 2 倍高速なようです...そのため、「なぜ Java も AOT を使用しないのか?」と考えました。とにかく、私が収集できる主な違いは、JIT が実行時に適応最適化を使用することです。これにより、(たとえば) 頻繁に実行されるバイトコードの部分のみをネイティブ コードにコンパイルできます。一方、AOT はソース コード全体をネイティブ コードにコンパイルし、量の少ないコードは量の多いコードよりも高速に実行されます。
ほとんどの Android アプリは少量のコードで構成されていると想像する必要があるため、平均して、ソース コード全体をネイティブ コード AOT にコンパイルし、解釈/最適化に関連するオーバーヘッドを回避する方が理にかなっています。

于 2014-03-07T16:54:46.643 に答える