web-dev-qa-db-ja.com

ジャストインタイムコンパイルと事前コンパイルの利点は何ですか?

私は最近それについて考えてきましたが、 [〜#〜] jit [〜#〜] コンパイルに与えられるほとんどの利点は多かれ少なかれに起因するように思えます代わりに中間形式であり、それ自体はコードを生成するのにあまり良い方法ではありません。

したがって、これらは主に pro-JIT コンパイル引数です。

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

ahead-of-time コンパイルにも利点がなかったわけではありません。 Just-in-time コンパイルには時間の制約があります。プログラムの起動中にエンドユーザーを永遠に待たせることはできないため、どこかで行うことがトレードオフになります。ほとんどの場合、彼らは最適化を減らします。私の友人はプロファイリングの証拠を持っていて、関数をインライン化し、ループを「手動で」展開する(プロセスのソースコードを難読化する)ことでパフォーマンスにプラスの影響があった C#数値計算プログラム。同じタスクを [〜#〜] c [〜#〜] プログラムで実行して、同じことを私の側で行っても、肯定的な結果は得られず、これは私のコンパイラが許可された広範な変換。

それにもかかわらず、私たちはジットプログラムに囲まれています。 C# Java はどこにでもあり、Pythonスクリプトはある種のバイトコードにコンパイルできます。他の多くのプログラミング言語が同じことをしていることを確認してください。私が行方不明になっている正当な理由があるに違いありません。ジャストインタイムコンパイルが ahead-of-time コンパイル?


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

ほとんどのランタイム(またはコンパイラー)は、それらをジャストインタイムまたは事前にコンパイルすることを好みます。 ahead-of-time コンパイルは、コンパイラーが最適化を実行する時間があるため、より良い代替手段のように見えるので、Microsoft、Sun、その他すべてがなぜそうなるのか疑問に思っています他の方法で。 just-in-time コンパイルされたプログラムでの経験では基本的な最適化が不十分であったため、プロファイリング関連の最適化については少し疑っています。

ahead-of-time コンパイルと just-in-time コンパイルの例が必要なため、Cコードの例を使用しました。 [〜#〜] c [〜#〜] コードが中間表現に出力されなかったという事実は、 ahead-of-time コンパイルは、より良い即時結果をもたらすことができます。

68
zneak

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

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

ジャストインタイムでコンパイルされた実行可能ファイルは、通常、次の場合に優位を占めます。

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

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

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

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

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

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

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

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

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

34
Thilo

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

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

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

6
vava
  1. より良い反射のサポート。これは、事前にコンパイルされたプログラムで原則的に実行できますが、実際にはほとんど発生しないようです。

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

4
dsimcha

このアイデアはDart言語で実装されているようです:

https://hackernoon.com/why-flutter-uses-Dart-dd635a054ebf

JITコンパイルは開発中に使用され、特に高速なコンパイラを使用します。その後、アプリのリリース準備が整うと、AOTがコンパイルされます。その結果、高度なツールとコンパイラの助けを借りて、Dartは両方の長所を提供できます:非常に高速な開発サイクル、高速な実行と起動時間。

2

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

2
Scott Ferrell

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

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

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

2
ChaseMedallion

たぶんそれはプログラミングに対する現代的なアプローチに関係しているのかもしれません。何年も前にあなたはプログラムを紙に書き、他の人はそれをパンチカードのスタックに変えてコンピューターに送り込み、明日の朝は計量紙にクラッシュダンプを得るでしょう半ポンド。コードの最初の行を書く前に、多くのことを考えることを余儀なくされたすべて。

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

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

1
Dmitry Leskov

Platform-b​​rowser-dynamicとplatform-b​​rowserの違いは、angularアプリのコンパイル方法です。動的プラットフォームを使用すると、angularフロントエンドおよびアプリケーションへのインタイムコンパイラー。これは、アプリケーションがクライアント側でコンパイルされていることを意味します。一方、プラットフォームブラウザーを使用すると、プリコンパイル済みバージョンのAhead-of-Timeブラウザーに送信されるアプリケーション(通常、ブラウザーに送信されるパッケージは非常に小さいことを意味します) https://angular.io/docs/ts/latest/guide/ngmodule.html #!#bootstrap で詳細を説明しています。

0