私の教授が小さなプログラムで非公式のベンチマークを行ったところ、Java の時間は最初の実行で 1.7 秒、その後の実行で 0.8 秒でした。
これは完全にランタイム環境をオペレーティング環境にロードしたことによるものですか?
また
Java がコードを最適化し、それらの最適化の結果を保存することの影響ですか (申し訳ありませんが、その専門用語はわかりません)。
私の教授が小さなプログラムで非公式のベンチマークを行ったところ、Java の時間は最初の実行で 1.7 秒、その後の実行で 0.8 秒でした。
これは完全にランタイム環境をオペレーティング環境にロードしたことによるものですか?
また
Java がコードを最適化し、それらの最適化の結果を保存することの影響ですか (申し訳ありませんが、その専門用語はわかりません)。
さて、私はそれを読んだ場所を見つけました。これはすべて「Learning Java」(O'Reilly 2005) からのものです。
従来の JIT コンパイルの問題は、コードの最適化に時間がかかることです。そのため、JIT コンパイラは適切な結果を生成できますが、アプリケーションの起動時にかなりのレイテンシが発生する可能性があります。これは通常、長時間実行されるサーバー側アプリケーションの問題ではありませんが、機能が制限された小さなデバイスで実行されるクライアント側ソフトウェアおよびアプリケーションにとっては深刻な問題です。これに対処するために、HotSpot と呼ばれる Sun のコンパイラ テクノロジは、適応コンパイルと呼ばれるトリックを使用します。プログラムが実際に何に時間を費やしているかを見ると、コードの比較的小さな部分を繰り返し実行することにほぼすべての時間を費やしていることがわかります。繰り返し実行されるコードのチャンクは、プログラム全体のごく一部にすぎない場合がありますが、その動作によってプログラムの全体的なパフォーマンスが決まります。
この事実を利用するために、HotSpot は通常の Java バイトコード インタープリターとして開始しますが、違いがあります。実行中のコードを測定 (プロファイル) して、どの部分が繰り返し実行されているかを確認します。コードのどの部分がパフォーマンスにとって重要であるかを認識すると、HotSpot はそれらのセクションを最適なネイティブ マシン コードにコンパイルします。プログラムのごく一部のみをマシンコードにコンパイルするため、それらの部分を最適化するのに必要な時間をかける余裕があります。プログラムの残りの部分は、コンパイルする必要がまったくなく、解釈するだけで、メモリと時間を節約できます。実際、Sun のデフォルトの Java VM は、クライアントとサーバーの 2 つのモードのいずれかで実行できます。これらのモードは、起動時間の短縮とメモリの節約を重視するか、パフォーマンスをフラットにするかを決定します。
この時点で自然に疑問に思うのは、「アプリケーションがシャットダウンするたびに、この優れたプロファイリング情報をすべて破棄するのはなぜですか?」ということです。Sun は、Java 5.0 のリリースで、最適化された形式で永続的に格納される読み取り専用の共有クラスを使用して、このトピックを部分的に切り開きました。これにより、特定のマシンで多くの Java アプリケーションを実行する際の起動時間とオーバーヘッドの両方が大幅に削減されます。これを行うための技術は複雑ですが、考え方は単純です。つまり、プログラムの高速化が必要な部分を最適化し、残りの部分については気にする必要はありません。
Java 5.0 以降、Sun はどこまでそれを実現してきたのだろうか。
プログラムの呼び出しの間に統計的な使用状況データを保存する、広く使用されている仮想マシンを私は知りませんが、将来の研究にとって興味深い可能性があることは確かです。
あなたが見ているのは、ほぼ間違いなくディスクキャッシングによるものです。
ディスクキャッシングの結果である可能性が高いことに同意します。
参考までに、IBM Java 6 VM には事前コンパイラ (AOT) が含まれています。コードは、JIT が生成するものほど最適化されていませんが、複数の VM にまたがって保存されているため、ある種の永続的な共有メモリが存在すると考えられます。その主な利点は、起動時のパフォーマンスを向上させることです。デフォルトでは、IBM VM は 1000 回呼び出された後にメソッドを JIT します。VM の起動時にメソッドが 1000 回呼び出されることがわかっている場合 (一般的に使用される のようなメソッドを考えてjava.lang.String.equals(...)
ください)、それを AOT キャッシュに格納して、コンパイルに時間を浪費する必要がないようにすることは有益です。ランタイム。
ポスターに見られるパフォーマンスの違いは、JREをメモリに取り込むディスク遅延が原因である可能性が高いことに同意します。Just In Timeコンパイラ(JIT)は、小さなアプリケーションのパフォーマンスに影響を与えません。
Java 1.6u10(http://download.java.net/jdk6/)は、バックグラウンドプロセスでランタイムJARにアクセスし(Javaが実行されていない場合でも)、データをディスクキャッシュに保持します。これにより、起動時間が大幅に短縮されます(これは、デスクトップアプリにとっては大きなメリットですが、サーバー側のアプリにとってはおそらくわずかな価値です)。
大規模で長時間実行されるアプリケーションでは、JITは時間の経過とともに大きな違いをもたらしますが、JITが開始して最適化するのに十分な統計を蓄積するのに必要な時間(5〜10秒)は、全体の寿命に比べて非常に短いです。アプリケーションの(ほとんどの場合、数か月および数か月間実行されます)。JITの結果を保存および復元することは興味深い学術的演習ですが、実際の改善はそれほど大きくありません(そのため、JITチームはメモリキャッシュミスを最小限に抑えるためのGC戦略などに重点を置いています...)。
ランタイムクラスの事前コンパイルは、デスクトップアプリケーションにかなり役立ちます(前述の6u10ディスクキャッシュの事前ロードも同様です)。
ベンチマークがどのように行われたかを説明する必要があります。特に、時間の測定を開始する時点です。
JVM の起動時間を含めると (ユーザー エクスペリエンスのベンチマークには役立ちますが、Java コードの最適化にはあまり役立ちません)、ファイルシステムのキャッシュ効果であるか、「Java クラス データ共有」と呼ばれる機能が原因である可能性があります。
サンの場合:
http://java.sun.com/j2se/1.5.0/docs/guide/vm/class-data-sharing.html
これは、JVM がランタイム クラスの準備されたイメージをファイルに保存し、次回の起動時にそれらをすばやくロード (および共有) できるようにするオプションです。これは、Sun JVM で -Xshare:on または -Xshare:off を使用して制御できます。デフォルトは -Xshare:auto で、共有クラス イメージが存在する場合はそれをロードし、存在しない場合はディレクトリが書き込み可能であれば最初の起動時に書き込みます。
IBM Java 5 では、これはさらに強力です。
http://www.ibm.com/developerworks/java/library/j-ibmjava4/
JIT統計を保存している主流のJVMを知りません。
Java JVM (実際には、JVM のさまざまな実装から変更される可能性があります) は、最初の起動時にバイト コードを解釈します。コードが十分な回数実行されることを検出すると、ネイティブのマシン言語に JIT して、より高速に実行します。