JVMがJITコンパイル済みコードをキャッシュしないのはなぜですか?


107

Sunの標準的なJVM実装は、かなり洗練された最適化をバイトコードに適用して、コードが数回実行された後、ネイティブに近い実行速度を取得します。

問題は、このコンパイルされたコードが、同じ関数/クラスの後続の使用中に使用するためにディスクにキャッシュされないのはなぜですか?

現状では、プログラムが実行されるたびに、JITコンパイラは、コンパイル済みのバージョンのコードを使用するのではなく、新たに起動します。この機能を追加すると、バイトコードが本質的に解釈されているときに、プログラムの最初の実行時間が大幅に増加しませんか?


4
この問題を論じているスレッド:javalobby.org/forums/thread.jspa?threadID
miku

2
しかし、決定的な答えを引き付ける可能性の低い質問。
bmargulies

1
メモリーをJITするのではなく、ディスクからJITされたものをロードする必要があるため、「大幅な」ブーストについてはわかりません。スピードアップすることはできますが、ケースバイケースです。
R.マルティーニョフェルナンデス

1
皆さん、素晴らしい回答をありがとう!すべての回答は等しく有効だったので、私はこの問題についてコミュニティと一緒に行きました...
Chinmay Kanchi 2010

これはあなたが私に尋ねるなら良い質問です:)
アルフレッド

回答:


25

@MYYNが投稿したリンクのカットアンドペーストに頼らずに、これは、JVMが実行する最適化が静的ではなく動的であり、データパターンとコードパターンに基づいているためと考えられます。これらのデータパターンはアプリケーションの存続期間中に変更され、キャッシュされた最適化が最適ではなくなる可能性があります。

したがって、保存された最適化がまだ最適であるかどうかを確認するメカニズムが必要です。


6
...または、オラクルのJVMのように、永続性をオプションとして提供することもできます- 高度なプログラマー、パターンが変化していないことがわかっているときに、その場所でアプリケーションのパフォーマンスを最適化できるようにします。何故なの?!
Alex Martelli、2010年

2
それはおそらく価値がないので。SUN、IBM、BEAのどちらも、JVMのパフォーマンスに価値があると考えていなかった場合、それには正当な理由があります。おそらく、RTの最適化はOracleのそれよりも速いため、Oracleがそれをキャッシュします。
skaffman、2010年

9
以前の実行で学んだことを使用するために、保存された最適化を開始点として使用しないのはなぜですか?そこから、JITは通常どおり、再最適化されたものを機能させることができます。シャットダウン時に、そのコードは再び永続化され、次の実行で新しい開始点として使用できます。
Puce

1
@Puce私が考えることができる唯一の理由は、私の知る限り、最適化されたコードの実行からプロファイリング統計を取得できないことです。したがって、改善する方法はありません...
maaartinus 14

1
私は個人的には、「実行間でJITプロファイリング情報を保持する」オプションで、「これはまったく同じJVM、同じデータなどでのみ有効であり、それ以外は無視される」というすべての警告が表示されます。これが実装されていない理由に関しては、JITシードデータの永続化と検証の複雑さが増しすぎて、他のプロジェクトからリソースを取得できないと思います。これとJava 8ラムダ+ストリームのどちらかを選択した場合は、後者を使用します。
–ThorbjørnRavn Andersen、2015

25

OracleのJVMは確かにそのように文書化されています-Oracleを引用すると、

コンパイラーは、Oracle JVMのクラス解決モデルを利用して、データベースの呼び出し、セッション、またはインスタンス全体でコンパイルされたJavaメソッドをオプションで永続化できます。このような永続性により、セマンティックにJavaコードが変更されていないことがわかっている場合、セッションまたはインスタンス間での不要な再コンパイルのオーバーヘッドが回避されます。

すべての洗練されたVM実装が同様のオプションを提供しない理由はわかりません。


8
他の洗練されたJVMには、物を格納するのに便利なすばらしいエンタープライズRDBMSがありません:)
skaffman

うわー!つまり、コンパイルは時々キャッシュされます。これは良い知らせです!
Sandeep Jindal 2013年

IBMのJ9もそのように文書化されています。
user314104 2014年

9
このOracle JVMはOracleデータベース内のものであり、Sunの購入時にOracleがダウンロードしたものではないことに注意してください。
–ThorbjørnRavn Andersen 2015

14

既存の回答の更新-Java 8には、これを解決するためのJEPがあります。

=> JEP 145:コンパイルされたコードのキャッシュ新しいリンク

非常に高いレベルで、その明記された目標は次のとおりです

大規模なJavaアプリケーションの起動時間を改善するために、以前の実行からコンパイルされたネイティブコードを保存して再利用します。

お役に立てれば。


3
この機能は最終リリースには至っていません。
assylias 2014

5

Excelsior JETには、2001年にリリースされたバージョン2.0以降のキャッシュJITコンパイラがあります。さらに、そのAOTコンパイラは、すべての最適化を使用して、キャッシュを単一のDLL /共有オブジェクトに再コンパイルする場合があります。


3
はい、しかし問題は正規のJVM、すなわちSunのJVMについてでした。Java用のAOTコンパイラーや他のキャッシングJVMがいくつかあることはよく知っています。
Chinmay Kanchi、2010

0

JVMの実装に関与していない実際の理由はわかりませんが、もっともらしい理由はいくつか考えられます。

  • Javaのアイデアは、一度だけ実行される任意の場所の言語であり、クラスファイルにプリコンパイルされたものを入れることは一種の違反です(もちろん、実際のバイトコードはまだ存在するため、「一種」のみ)
  • 特に、同じプログラムを複数の異なるJVMで実行した場合は、クラスファイルのサイズが大きくなります(異なるバージョンを異なるJVMであると考える場合、これは実際には珍しくありません)。本当にしなければならない)
  • クラスファイル自体は書き込み可能でない可能性があります(それを確認するのはかなり簡単ですが)
  • JVM最適化は実行時情報に部分的に基づいており、他の実行ではそれらは適切でない可能性があります(ただし、いくつかの利点は提供されるはずです)

しかし、私は本当に推測しており、ご覧のとおり、私の理由のいずれかが実際のショーストッパーであるとはあまり考えていません。私はSunがこのサポートを優先事項と見なしていないと考えています。おそらく私の最初の理由は真実に近いでしょう。これを習慣的に行うと、Javaクラスファイルが実際にはVMごとに個別のバージョンを必要とするのではなく、クロスプラットフォーム。

私の優先する方法は、実際に前もって明示的にこのようなことを行うために使用できる個別のバイトコードからネイティブへのトランスレータを持ち、特定のVM用に明示的に構築されたクラスファイルを作成することです。異なるVMでも実行できます。しかし、それはおそらく私の経験によるものです。私はほとんどJava MEを行ってきましたが、Javaコンパイラーがコンパイルに関して賢くないのは本当に痛いです。


1
そのようなもののためのクラスファイルにスポットがあります。それは、本来の意図であった事実です(JITされたコードをクラスファイルの属性として格納します)。
TofuBeer

@TofuBeer:確認ありがとうございます。私はそうであるのではないかと思っていました(それが私がしたことです)が、確信がありませんでした。考えられる理由からそれを削除するように編集されました。
JaakkoK、2010年

最後の弾丸で頭の釘を打ったと思います。他のものは回避できますが、最後の部分は、JITされたコードが永続化されない主な理由だと思います。
Sasha Chedygov、2010年

1
明示的なバイトコードからネイティブコンパイラーに関する最後の段落は、現在NGENを使用した.NETにあるものです(msdn.microsoft.com/en-us/library/6t9t5wcf(VS.71).aspx)。
R.マルティーニョフェルナンデス2010
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.