プログラムのコンパイルとコードの最適化、ランタイムの最適化

ジャストインタイムコンパイラ

一部の商用仮想マシン(Sun HotSpot、IBM J9)では、Javaプログラムは最初にインタープリター(インタープリター)によって解釈および実行されます。仮想マシンがメソッドまたはコードブロックが頻繁に実行されていることを検出すると、これらを配置しますコードは「ホットスポットコード」(ホットスポットコード)として識別されます。ホットスポットコードの実行効率を改善するために、仮想マシンは実行時にこれらのコードをローカルプラットフォームに関連するマシンコードにコンパイルし、さまざまなレベルの最適化を実行します。このタスクを完了するコンパイラは、ジャストインタイムコンパイラと呼ばれます(ちょうどTime Compilerでは、以下ではJITコンパイラと呼びます

ホットスポット仮想マシンのジャストインタイムコンパイラ

1.コンパイラーとインタープリター

コンパイラとインタプリタには独自の利点があります

プログラムをすばやく起動して実行する必要がある場合、インタープリターが最初に役割を果たし、コンパイル時間を節約してすぐに実行できます。

プログラムの実行後、時間が経つにつれてコンパイラが徐々に役割を果たし、ますます多くのコードがローカルコードにコンパイルされると、より高い実行効率を得ることができます。

プログラム実行環境(一部の組み込みシステムなど)でメモリリソースの制限が大きい場合、インタープリター実行を使用してメモリを節約できます。それ以外の場合は、コンパイルされた実行を使用して効率を向上できます。同時に、インタプリタはコンパイラの積極的な最適化の「エスケープゲート」としても使用できるため、コンパイラは確率に応じてほとんどの場合実行速度を向上できるいくつかの最適化方法を選択できます。ポストタイプの継承構造が変更され、「一般的でないトラップ」が表示された場合、逆最適化(非最適化)によって解釈された状態に戻して実行を継続できます。そのため、仮想マシン実行アーキテクチャ全体では、インタープリターとコンパイラーが連携して動作することがよくあります。写真

インタープリターとコンパイラーを一緒に使用する方法は、仮想マシンでは**「混合モード」と呼ばれます。ユーザーは、パラメーター「-Xint」を使用して、仮想マシンを「解釈済みモード」で強制的に実行できます**、このとき、コンパイラーはまったく介入せず、すべてのコードが解釈された方法で実行されます。

パラメータ** "-Xcomp"を使用して、仮想マシン強制的に "コンパイルモード" **で実行することもできます。現時点では、コンパイルモードが推奨されますが、コンパイルを実行できない場合でも、インタプリタは実行プロセスに介入する必要があります。写真

階層化コンパイル

HotSpot仮想マシン Jではdk1.7 サーバー仮想マシンのモードをデフォルトのコンパイラの戦略がオンになっているよう。

  • レベル0、プログラムの解釈と実行、インタープリターはパフォーマンス監視機能(プロファイリング)を開かず、コンパイルの最初のレベルをトリガーできます
  • 最初の層はC1コンパイルとも呼ばれ、バイトコードをローカルコードにコンパイルしてシンプルで信頼性の高い最適化を行い、必要に応じてパフォーマンスモニタリングロジックを追加します。
  • レイヤー2(またはそれ以上)(C2コンパイルとも呼ばれます)もバイトコードをローカルコードにコンパイルしますが、コンパイルに時間がかかる最適化を有効にし、パフォーマンス監視情報に基づいて信頼性の低い積極性を実行します最適化

:階層化コンパイルを実装すると、クライアントコンパイラとサーバーコンパイラが同時に動作します。多くのコードが複数回コンパイルされる可能性があります。クライアントコンパイラを使用してコンパイル速度を上げ、サーバーコンパイラを使用してコンパイル品質を高めます。実行中にパフォーマンス監視情報を収集する必要はありません。

2.コンパイルされたオブジェクトとトリガー条件

動作中にインスタントコンパイラによってコンパイルされる「ホットコード」には、次の2つのタイプがあります。

  • 複数回呼び出されたメソッド
  • ループ本体が複数回実行されました

最初のケースの場合、コンパイラーはメソッド全体をコンパイルオブジェクトとして受け取り、このコンパイルは仮想マシンの標準JITコンパイルメソッドでもあります。2番目のタイプの場合、コンパイルアクションはループ本体によってトリガーされますが、コンパイラーは(個別のループ本体ではなく)メソッド全体をコンパイルオブジェクトとして使用します。このコンパイル方法は、メソッドの実行中にコンパイルが行われるため、On Stack Replacement(OSRコンパイルの略)と呼ばれます。つまり、メソッドスタックフレームはスタック上にあり、メソッドは置き換えられます。

ホットスポットの検出

  • サンプルベースのホット検出(サンプルベースのホット検出):このメソッドを使用する仮想マシンは、各スレッドのスタックのトップを定期的にチェックします。メソッド(またはいくつか)のメソッドがスタックのトップで頻繁に見つかる場合、このメソッドは "ホットスポット方式」。
  • カウンターベースのホットスポット検出(カウンターベースのホットスポット検出):この方法を使用する仮想的な機会は、各メソッド(コードブロックを含む)のカウンターを確立します。統計的メソッドの実行回数が特定のしきい値を超えると、「ホットスポットメソッド」と見なされます。 。

使用HotSpot仮想マシンが第二-それに基づいてカウンタホットスポット検出方法は、各方法のためにカウンタの二種類を準備し:メソッド呼び出しカウンタ(呼び出しカウンタ)とカウンタの背面側(後縁カウンタ)

メソッド呼び出しカウンター

統計メソッドが呼び出される回数。デフォルトのしきい値は、クライアントモードで1500回、サーバーモードで10,000回です。仮想マシンパラメーター-XX:CompileThresholdで手動で設定できます。

メソッドが呼び出されると、まずメソッドのJITコンパイルバージョンが存在するかどうかをチェックし、存在する場合は、コンパイルされたローカルコードを使用して最初に実行されます。存在しない場合は、メソッド呼び出しカウンタの値を1つ増やし、メソッド呼び出しカウンタとバックサイドカウンタの合計がメソッド呼び出しカウンタのしきい値を超えているかどうかを判断します。しきい値を超えると、このメソッドのコードコンパイル要求がインスタントコンパイラに送信されます。

何も設定しない場合、メソッド呼び出しカウンターはメソッドが呼び出された絶対回数をカウントしませんが、相対的な実行頻度、つまり、一定期間内にメソッドが呼び出された回数をカウントします。一定の時間制限を超えると、メソッド呼び出しの数がまだコンパイルのためにリアルタイムコンパイラーに送信されるのに十分でない場合、メソッド呼び出しカウンターは半分に減少します。このプロセスは、メソッド呼び出しカウンター減衰(Counter Decay)と呼ばれます。この期間はこのメソッドのカウンター半減期(Counter Half Life Time)と呼ばれます。仮想マシンがガベージコレクションを実行するまでに熱減衰のアクションが実行されます。仮想マシンパラメータ-XX:-UseCounterDecayを使用して熱減衰をオフにし、メソッドカウンタにメソッド呼び出しの絶対数をカウントさせることができます。-XX:CounterHalfLifeTimeパラメーターを使用して、半減期を秒単位で設定できます。

裏面カウンター

メソッド内でループ本体コードが実行された回数をカウントします。バイトコード内で逆方向の制御フロージャンプに遭遇する命令は、「バックエッジ」と呼ばれます。明らかに、バックカウント統計を確立する目的は、OSRコンパイルをトリガーすることです。

バックエッジカウンターのしきい値。HotSpot仮想マシンは、メソッドコールカウンターのしきい値と同様のパラメーターも提供しますが、ユーザーが設定するために-XX:CompileThreshold -XX:BackEdgeThresholdを使用しますが、現在の仮想マシンは実際にはこのパラメーターを使用しません。したがって、バックエッジカウンターのしきい値を間接的に調整するには、別のパラメーター-XX:OnStackReplacePercentageを設定する必要があります。計算式は次のとおりです。

  • クライアントモード:

    方法调用计数器阈值 X OSR比率 / 100
    

OSR比率のデフォルト値は933です。デフォルト値が採用されている場合、クライアントモード仮想マシンのバックエッジカウンターのしきい値は13995です。

  • サーバーモード:

     方法调用计数器阈值 X (OSR比率 - 解释器监控比率)/ 100 
    

このうち、OSRのデフォルト値は140、インタープリター監視率のデフォルト値は33です。デフォルト値を採用した場合、サーバーモード仮想マシンのバックエッジカウンターのしきい値は10700になります。

3.コンパイルプロセス

デフォルト設定では、それがメソッド呼び出しまたはOSRコンパイル要求によって生成されたリアルタイムコンパイル要求であるかどうかにかかわらず、仮想マシンはコードコンパイルが完了する前に解釈メソッドに従って実行を継続し、コンパイルアクションはバックグラウンドコンパイルスレッドで実行されます。ユーザーは、パラメーター-XX:-BackgroundCompilationを介してバックグラウンドコンパイルを無効にできます。バックグラウンドコンパイルを無効にした後、JITコンパイル条件が満たされると、実行スレッドはコンパイルリクエストが仮想マシンに送信されるまで待機し、コンパイルプロセスが完了するまで待機します。デバイスが出力するローカルコード。

クライアントコンパイラシンプルで高速な3ステージコンパイラ

第一段階

プラットフォームに依存しないフロントセクションは、バイトコードを高レベルの中間表現(HIR)に構築します。HIRは**静的単一割り当て(SSA)**の形式を使用してコード値を表します。これにより、HIRの構築中および構築後に実行されるいくつかの最適化アクションを実装しやすくなります。この前に、コンパイラーはメソッドのインライン化、定数の伝播など、バイトコードのいくつかの基本的な最適化を完了します。

第二段階

プラットフォーム関連のバックエンドはHIRから低レベルの中間表現(LIR)を生成します。その前に、NULL値のチェックの削除、範囲のチェックの削除などの他の最適化がHIRで完了し、HIRより効率的なコード表現を実現します。

第三段階

これは、線形スキャンレジスタ割り当てアルゴリズムを使用して、プラットフォーム関連のバックエンドのLIRにレジスタを割り当て、LIRでピープホール最適化を実行してから、マシンコードを生成します。写真

サーバーコンパイラ

サーバーコンパイラは、サーバー側の一般的なアプリケーション専用のコンパイラであり、サーバー側のパフォーマンス構成用に特別に調整されていません。また、完全に最適化された高度なコンパイラであり、-O2パラメータを使用してGUN C ++コンパイラの最適化強度にほぼ到達できます。不要なコードの削除、ループの展開、ループ式の外挿、共通の部分式の削除、定数の伝播、基本的なブロックの並べ替えなど、すべての古典的な最適化アクションを実行します。Java言語機能に密接に関連するいくつかの最適化も実装します範囲チェックの除去やnull値チェックの除去などの手法。さらに、インタプリタまたはクライアントコンパイラによって提供されるパフォーマンス監視情報に基づいて、インラインおよび分岐頻度予測の保護など、不安定で積極的な最適化が実行される場合があります。

コンパイル最適化技術

一般的な部分式の除去

式Eが既に計算されていて、Eのすべての変数の値が前の計算から現在の値に変更されていない場合、このEのオカレンスはパブリックサブ式になります。この式の場合、計算に時間をかける必要はなく、Eを以前に計算された式の結果で直接置き換えます。

この最適化は、プログラムの基本ブロックに限定されている場合は、呼ばれる地元の共通部分式除去この最適化は、基本的な複数のブロックをカバーする場合、それが呼び出され、(ローカル共通部分式除去)グローバルな部分式の除去(グローバル共通部分式除去)

アレイ境界チェックの排除

メソッドのインライン化

メソッドのインライン化は、コンパイラーの最も重要な最適化メソッドの1つです。メソッド呼び出しのコストを削減することに加えて、他の最適化メソッドの適切な基盤を確立することがより重要です。

メソッドのインライン化の最適化動作は非常に単純に見えますが、実際のメソッド呼び出しを回避するために、呼び出しを開始したメソッドにターゲットメソッドのコードを「コピー」することです。しかし、実際には、Java仮想マシンのインライン化プロセスはそれほど単純ではありません。それは、リアルタイムコンパイラーが特別な努力をしなかった場合、古典的なコンパイル原理の最適化理論によれば、ほとんどのJavaメソッドはインライン化できないためです。

エスケープ分析

エスケープ分析は、現在のJava仮想マシンで最も高度な最適化テクノロジーです。型継承の分析と同様に、エスケープ分析はコードを直接最適化する手段ではなく、他の最適化方法の基礎を提供する分析手法です。

エスケープ分析の基本的な動作は、オブジェクトの動的スコープを分析することです。オブジェクトがメソッドで定義されている場合、それは外部メソッドによって参照される可能性があります。たとえば、メソッドエスケープと呼ばれる他のメソッドに呼び出しパラメーターとして渡されますスレッドエスケープと呼ばれる他のスレッドでアクセスできるクラス変数またはインスタンス変数への割り当てなど、外部スレッドからもアクセスできます

メソッドがメソッドまたはスレッドの外にエスケープしないことを証明できる場合は、この変数に対していくつかの効率的な最適化を実行できます。

  • スタック割り当て:オブジェクトがメソッドをエスケープしないと判断された場合は、このオブジェクトにスタック上のメモリを割り当てさせることをお勧めします。オブジェクトが占有するメモリ空間は、スタックフレームでポップできます。そして破壊された。一般的なアプリケーションでは、エスケープされないローカルオブジェクトの割合は非常に大きくなります。スタックの割り当てを使用できる場合、メソッドの終了時に多数のオブジェクトが自動的に破棄され、ガベージコレクションシステムへの圧力は小さくなります。たくさん。
  • 同期の排除:スレッドの同期自体は比較的時間がかかるプロセスです。エスケープ分析で変数がスレッドをエスケープせず、他のスレッドからアクセスできないと判断できる場合、この変数の読み取りと書き込みの競合は発生しません。この変数に実装された同期手段も削除できます。
  • スカラー置換スカラーとは、データの一部を小さなデータに分解できなくなることを指します。Java仮想マシンの元のデータ型(int、long、およびその他の数値型と参照型など)をさらに分解することはできません。 、それらはスカラーと呼ぶことができます。対照的に、データの一部が引き続き分解される可能性がある場合、そのデータは集約と呼ばれ、Javaのオブジェクトが最も一般的な集約です。プログラムへのアクセス状況に応じて、Javaオブジェクトを解体する場合は、Javaオブジェクトが使用するメンバー変数を元の型に復元してアクセスすることをスカラー置換と呼びます。エスケープ分析により、オブジェクトが外部からアクセスされないことが判明し、このオブジェクトを逆アセンブルできる場合、プログラムが実際に実行されると、このオブジェクトは作成されず、このメソッドで使用されるいくつかのメンバー変数が直接作成されます。交換する。

必要に応じて、プログラムの操作に有益であることが確認された場合、ユーザーはパラメーター-XX:+ DoEscapeAnalysisを手動で使用してエスケープ分析を開始できます。開いた後、パラメーター**-XX:+ PrintEscapeAnalysisによって分析結果を表示できます。エスケープ分析サポートにより、ユーザーはパラメーター -XX:+ EliminateAllocations を使用してスカラー置換を有効にし、 + XX:+ EliminateLocks を使用して同期除去を有効にし、パラメーター -XX:+ PrintEliminateAllocation **を使用してスカラーの置換を表示できます。


上記のナレッジポイントは、「Java仮想マシンの詳細な理解」からの抜粋です。

オリジナルの記事を8件公開 Like1 訪問数259

おすすめ

転載: blog.csdn.net/qq_40635011/article/details/105626865