2

私が読んだことから、Java(通常)はJavaをあまり(まったく?)最適化されていないJavaバイトコードにコンパイルし、最適化するためにjitに任せているようです。これは本当ですか?そして、そうであれば、コンパイラーにコードを最適化させて、jit が行う作業が少なくなるようにするための調査が (おそらく代替実装で) 行われましたか (これは可能ですか)?

また、移植性の喪失などの多くの理由から、Java (および他の多くの高レベルのメモリ管理言語) のネイティブ コード生成 (事前コンパイルと呼ばれることもあります) を嫌う人が多いようですが、また、部分的には(少なくともジャストインタイムコンパイラを備えた言語の場合)、マシンコードへの事前コンパイルはjitコンパイラによって実行できる最適化を見逃すため、長期的には遅くなる可能性があると考えられているためです.

これは、誰かがhttp://en.wikipedia.org/wiki/Profile-guided_optimization (バイナリ + いくつかのエクストラにコンパイルしてからプログラムを実行し、テスト実行のランタイム情報を分析して生成する)を実装しようとしたことがあるかどうか疑問に思いますJava/(他のメモリ管理言語) の現実世界での使用のために、より最適化されたバイナリであることが望まれますが、これは jit コードとどのように比較されますか? 誰にも手がかりがありますか?

4

3 に答える 3

4

個人的には、大きな違いは JIT コンパイルと AOT コンパイルではなく、クラス コンパイルとプログラム全体の最適化にあると思います。

javac を実行すると、単一の .java ファイルのみが参照され、単一の .class ファイルにコンパイルされます。すべてのインターフェイス実装と仮想メソッドおよびオーバーライドの有効性がチェックされますが、未解決のままです (プログラム全体を分析しないと、真のメソッド呼び出しターゲットを知ることは不可能であるため)。

JVM は「実行時の読み込みとリンク」を使用して、すべてのクラスを一貫したプログラムにアセンブルします (また、プログラム内のどのクラスも特殊な動作を呼び出して、デフォルトの読み込み/リンク動作を変更できます)。

ただし、実行時に、JVM は大部分の仮想メソッドを削除できます。すべてのゲッターとセッターをインライン化して、生のフィールドにすることができます。また、これらの生フィールドがインライン化されている場合、定数伝播を実行してコードをさらに最適化できます。(実行時には、プライベート フィールドのようなものはありません。) また、実行中のスレッドが 1 つしかない場合、JVM はすべての同期プリミティブを削除できます。

簡単に言うと、プログラム全体を分析しないと不可能な最適化がたくさんあります。プログラム全体の分析を行うのに最適な時期は実行時です。

于 2010-07-12T22:27:45.717 に答える
2

プロファイルに基づく最適化にはいくつかの注意点があります。そのうちの1つは、リンクしたWikiの記事でも言及されています。結果は有効です

  • 与えられたサンプルについて、ユーザーまたは他のコードが実際にコードをどのように使用しているかを表します。
  • 特定のプラットフォーム(CPU、メモリ+その他のハードウェア、OSなど)。
    パフォーマンスの観点からは、通常(多かれ少なかれ)同じと見なされるプラットフォーム間でもかなり大きな違いがあります(たとえば、シングルコア、512Mの古いAthlonと8Gの6コアIntel、Linuxで実行されているが非常に異なるカーネルバージョン)。
  • 指定されたJVMとその構成に対して。

これらのいずれかが変更された場合、プロファイリング結果(およびそれらに基づく最適化)はもはや有効である必要はありません。ほとんどの場合、最適化のいくつかは依然として有益な効果をもたらしますが、それらのいくつかは最適ではない(またはパフォーマンスを低下させる)ことが判明する可能性があります。

前述のように、JIT JVMはプロファイリングと非常によく似た処理を実行しますが、その場で実行します。実行されたコードを常に監視し、頻繁に実行されるホットスポットを探し、それらの部分のみを最適化しようとするため、「ホットスポット」とも呼ばれます。この時点で、コードに関するより多くの知識(コードのコンテキスト、他のクラスでの使用方法など)を活用できるようになるため、あなたや他の回答で述べられているように、より良い最適化を行うことができます。静的なもの。監視を継続し、必要に応じて後で最適化を実行しますが、今回はさらに困難になります(より多くのより高価な最適化を探します)。
実際のデータ(使用統計+プラットフォーム+構成)で作業することで、前述の警告を回避できます。

その価格は、「プロファイリング」+JIT-ingに費やす必要のある追加の時間です。ほとんどの場合、それは非常によく過ごしました。

プロファイルガイド付きオプティマイザーは、それでも競合する(または打ち負かす)ことができると思いますが、警告を回避できる場合は、一部の特別な場合に限ります。

  • サンプルが実際のシナリオを適切に表しており、実行中にあまり変化しないことは間違いありません。
  • ターゲットプラットフォームを非常に正確に把握しており、そのプラットフォームでプロファイリングを実行できます。
  • もちろん、JVMとその構成を知っている/制御している。

それはめったに起こらないでしょう、そして私は一般的にJITがあなたにより良い結果を与えると思います、しかし私はそれの証拠を持っていません。

JIT最適化を実行できないJVMをターゲットにしている場合、プロファイルに基づく最適化から価値を得るもう1つの可能性(ほとんどの小型デバイスにはそのようなJVMがあると思います)。

ところで、他の回答で言及されている1つの欠点は、回避するのが非常に簡単です。静的/プロファイルガイド付き最適化が遅い場合(おそらくそうです)、リリース(またはテスターに​​行くRC)またはナイトリービルド(時間がかかる場合)に対してのみ実行してくださいそれほど重要ではありません)。
はるかに大きな問題は、優れたサンプルテストケースを用意することだと思います。それらの作成と保守は通常簡単ではなく、多くの時間がかかります。特に、それらを自動的に実行できるようにしたい場合は、この場合は非常に重要です。

于 2010-07-21T07:53:59.063 に答える
1

公式のJava Hot Spotコンパイラは、実行時に「適応最適化」を行います。これは、あなたが言及したプロファイルに基づく最適化と本質的に同じです。これは、少なくともこの特定の Java 実装の長い間機能でした。

より多くの静的解析または最適化パスをコンパイル時に事前に実行することとのトレードオフは、基本的に、コンパイラの実行にかかる時間に対して、この余分な労力から得られる (常に減少する) リターンです。MLton (標準 ML 用) のようなコンパイラは、多くの静的チェックを備えたプログラム全体を最適化するコンパイラです。非常に優れたコードを生成しますが、中規模から大規模のプログラムでは、高速なシステムであっても非常に遅くなります。

そのため、Java のアプローチでは、JIT と適応最適化を可能な限り使用し、最初のコンパイル パスで許容可能な有効なバイナリを生成するだけのようです。絶対的な反対の目的は、MLKit のようなアプローチを使用することです。MLKit は、領域とメモリ動作の多くの静的推論を行います。

于 2010-07-20T22:06:51.513 に答える