JVMはどのようにしてメソッドをJITコンパイルする(メソッドを「ホット」として分類する)ことを決定しましたか?
私はすでに-XX:+PrintCompilation
、私はJITコンパイラの基本的なテクニックと、JITコンパイルが使用される理由を知っています。
それでも、JVMがメソッドのJITコンパイルをどのように決定するか、つまり「適切なタイミングでメソッドがJITコンパイルされるようになったとき」はまだわかりません。
すべてのメソッドが解釈され始め、「ホットメソッド」として分類されない限り、コンパイルされないという前提で正しいのでしょうか。頭の後ろに、メソッドが少なくとも10.000回実行された場合(メソッドを10.000回解釈した後、コンパイルされる)、「ホット」と見なされると書いてありますが、私はそれを認めなければなりません。これについて、または私がこれを読んだ場所がわからない。
だから私の質問を要約すると:
(1)Is everyメソッドが「ホット」メソッドとして分類されていない(したがってコンパイルされている)限り解釈されるか、「ホット」メソッドでなくてもメソッドがコンパイルされる理由があるか「?
(2)JVMはメソッドを「非ホット」メソッドと「ホット」メソッドにどのように分類しますか?実行回数は?他に何か?
(3)「ホット」メソッドに特定のしきい値(実行数など)がある場合、Javaフラグ(-XX:...
)このしきい値を設定するには?
HotSpotコンパイルポリシーは、特にJava 8でデフォルトでオンになっている階層化コンパイル)の場合、かなり複雑です。これは、実行回数ではなく、CompileThreshold
パラメータの問題でもありません。
最良の説明(どうやら、唯一の合理的な説明)はHotSpotソースで見つけることができます advancedThresholdPolicy.hpp を参照してください。
この高度なコンパイルポリシーの主なポイントを要約します。
- 実行はTier 0(インタープリター)から開始されます。
- コンパイルの主なトリガーはです。
- メソッド呼び出しカウンター
i
; - バックエッジカウンター
b
。後方分岐は通常、コード内のループを示します。
- メソッド呼び出しカウンター
カウンターが特定の頻度値(
TierXInvokeNotifyFreqLog
、TierXBackedgeNotifyFreqLog
)に達するたびに、現在実行中のメソッドで次に何を行うかを決定するために、コンパイルポリシーが呼び出されます。i
、b
の値、およびC1およびC2コンパイラスレッドの現在の負荷に応じて、次のように決定できます。- インタプリタで実行を継続します。
- インタプリタでプロファイリングを開始します。
- さらに再コンパイルするために必要な完全なプロファイルデータを使用して、層3でC1を使用してメソッドをコンパイルします。
- ティア2でC1を使用してメソッドをコンパイルします。プロファイルはありませんが、再コンパイルする可能性があります(可能性は低い)。
- 最後に、プロファイルもカウンターもない(同様にありそうもない)、Tier 1のC1でメソッドをコンパイルします。
ここで重要なパラメータは
TierXInvocationThreshold
とTierXBackEdgeThreshold
です。コンパイルキューの長さに応じて、特定のメソッドのしきい値を動的に調整できます。コンパイルキューはFIFOではなく、優先キューです。
プロファイルデータ(層3)を含むC1でコンパイルされたコードも同様に動作しますが、次のレベル(C2、層4)に切り替えるためのしきい値がはるかに大きくなります。例えば。インタプリタされたメソッドは、約200回の呼び出し後にティア3でコンパイルできますが、C1でコンパイルされたメソッドは、5000回以上の呼び出し後にティア4で再コンパイルされます。
- メソッドのインライン化には特別なポリシーが使用されます。小さなメソッドは、「ホット」でなくても呼び出し元にインライン化できます。少し大きいメソッドは、頻繁に呼び出される場合にのみインライン化できます(
InlineFrequencyRatio
、InlineFrequencyCount
)。
これを制御する主なパラメータは-XX:CompileThreshold=10000
Java= 8のホットスポットは、レベル1から4までのコンパイルの段階数を使用して、デフォルトで段階的コンパイルを使用するようになりました。1は最適化されていないと思います。レベル3はC1(クライアントクライアントに基づく) )、レベル4はC2(サーバーコンパイラに基づく)
つまり、予想よりも少し早く最適化が行われる可能性があり、10Kのしきい値に達した後もずっと最適化を続けることができます。私が見た最高のものは、100万回の呼び出し後にStringBuilderを排除するエスケープ分析です。
注:ループを何度も繰り返すと、コンパイラーがトリガーされます。例えば10K回のループで十分です。
1)メソッドが十分にホットであると見なされるまで、解釈されます。ただし、一部のJVM(Azul Zingなど)は起動時にメソッドをコンパイルでき、Hotspot JVMに内部APIを介してメソッドを強制的にコンパイルさせることができます。 Java 9にはAOT(Ahead Of Time)コンパイラも搭載されている可能性がありますが、まだ調査中です。
2)呼び出しの数、または反復の数。
3)はい-XX:CompileThreshold=
がメインです。