コンパイルJava言語は、大きく3つのタイプに分けることができます:
- コンパイラのフロントエンド、クラスファイルにコンパイル.javaファイル - .javaファイル - >の.class
- バックエンドプロセス実行時コンパイラJITコンパイラ(タイムコンパイラ)、マシンコードにバイトコード - .classファイル - >マシンコード
- 静的事前コンパイラAOT、.javaファイルがマシンコード--.javaにコンパイルされ、直接に - >マシンコード
別のコンパイル時には、コードの動作効率を向上させるためには、JVMはいくつかのコンパイラの最適化になります。
1、初期の最適化
初期の第1のコンパイラコンパイラ主として、即ちクラスファイルにコンパイルされた.javaファイルを、コンパイルプロセスは、3つの部分に分割されてもよいです。
- 分析及び充填シンボルテーブル
- 注釈プロセス注釈プラグインプロセッサ
- 分析バイトコード生成プロセス
1.1分析および充填シンボルテーブル
1.1.1字句解析
ソースコードの字句解析は、マーカーに文字ストリーム(トークン)のコレクションで、タグは、キーワード、変数名、リテラル、またはオペレータです。
例えば:INT A = B + 3; //このコードは、6つのマーカー、すなわちINT、、=、B、+ 3を含有します
1.1.2解析
トークン構文解析プロセスは、抽象構文木が道を示すために使用されるプログラムコードの構文を記述する木構造抽象構文木構造の配列である、構文木の各ノードは、例えば、統語構造にするプログラムコードを表しますパッケージタイプ、変性、オペレータインタフェースなど戻り値コードのコメントも文法的構造であってもよいです。
1.1.3充填シンボルテーブル
字句解析および構文解析が完了すると、次のステップでは、シンボルテーブルを埋めることです。シンボルテーブルはシンボルのセットとシンボルアドレス情報からなるテーブルです。
シンボルテーブル内の情報は、コンパイルのさまざまな段階で使用されます。意味解析、シンボル・テーブルの内容は、中間コードとセマンティックチェックを生成するための登録しました。シンボル名のアドレス割り当て、シンボルテーブルは割り当てられたアドレスに基づいて目標コード生成フェーズ、。
1.2注釈プロセッサ
注釈プロセッサは、読み取り、変更、任意の要素抽象構文木を追加することができます。注釈構文木の処理中に注釈プロセッサが変更されている場合、コンパイラは構文木を修正するためにプロセッサまでノーコメントまで、再起動シンボルテーブルと決意を埋める処理に戻り、各サイクルは、ラウンドと呼ばれています。注釈プロセッサを通過した後、それはコンパイラの動作を妨害し得ます。
1.3バイトコードの解析と意味解析
コンパイラは、プログラムコードの抽象構文木された後、構文木は、ソースコードが論理的であることを保証することはできません。セマンティック分析が正しいソースの構造の見直しの文脈の性質に関係しています。このような見直しの種類として。
標識および検査データと制御フロー解析プロセスは、意味解析に分かれています。
1.3.1マークをチェック
注釈内容は変数の代入と一致する変数の前のようにするかどうか、タイプ間で宣言されたデータが含まれているかどうか確認してください。
タグをチェックする過程で、このようなINT A = 1 + 2として定数畳み込み、あろう。演算量を増やすことなく、CPUの命令; //は整数、A = 3に折り畳まれます。
1.3.2フロー制御とデータ解析
プログラムロジックをさらに認証コンテキスト、それはすべての例外処理の問題を適切にチェックされた場合、各パスは、メソッドの戻り値を持っているかどうか、ローカル変数の割り当てがあるかどうかを確認することができます。
1.3.3構文糖液
糖衣構文は、これにより、エラーのプログラムコードの可能性、言語の機能に全く影響を軽減、読みやすさを向上させることができます。Javaは、一般的に自動、可変長パラメータ、トラバーサルサイクル、などの条件付きコンパイルを開梱、一般的なシンタックスシュガー、自動包装を使用しています。
構文糖溶液は糖衣構文は、コンパイル時にシンタックスシュガーは、単純な基本的な文法構造に戻すだろう動作している仮想マシンをサポートし、適切な場所にキャストを挿入しないことを意味します。
- ジェネリック医薬品は、ジェネリックメソッドのJava言語の実装では、型消去と呼ばれています。
- 自動ボクシングと対応する梱包方法や還元法に、自動的にアンボクシング。
- ループを通じて、なったイテレータを達成するために、コードのバックを置きます。
- そのような条件分岐のような条件付きコンパイル、コードブロックの確立を排除しないが場合は。
- 可変長パラメータは、アレイ型パラメータに変換されます。
1.3.4バイトコード生成
バイトコード生成は、コンパイルプロセスのjavacの最終段階です。情報は、バイトコードに前のステップで生成され、ディスクに書き込まれ、そのようなクラスおよびインスタンスのコンストラクタコンストラクタとして、コード変換作業を少量加えます。
2、高度な最適化(実行時の最適化)
メソッドまたは仮想マシンのコードブロックの発見は、これらの特別なコードを実行するときに頻繁にホットコードとして識別。実行時にホットコード、ネイティブプラットフォームに関連付けられたマシンコードにコンパイルされ、仮想マシンコード、および最適化の様々なレベルの効率を向上させるために、このタスクは、コンパイラ(JIT)コンパイラ時間と呼ばれます。
2.1時間のコンパイラとインタプリタ
2.1.1両者の関係
素早く起動および実行にするとプログラムのニーズ、インタプリタは、実行がすぐに解釈、コンパイル時間を節約することができ、メモリを節約することができます。プログラムが実行されると、コンパイラはより多くの置くことができ、より多くのコードは、効率を改善し、ネイティブコードにコンパイルされます。インタプリタとコンパイラが一緒に働くことができ、あなたはインタプリタからインタイムコンパイラを行くことができ、逆もまたインタプリタにコンパイラから最適化することができます。
タイムコンパイラ(JITコンパイラ)、クライアントサーバーコンパイラコンパイラに分けることができ、C1とC2コンパイラコンパイラと呼ばれます。JVMは、効率を達成するために、異なるプラットフォームに基づいて異なるコンパイラを選択します。
図:
2.1.2階層のコンパイル
異なるレベルに分割コンパイルする大きさと時間のかかる最適化するようにコンパイラをコンパイルするコンパイラに係る層状。
レイヤー0は、プログラムが解釈し、インタプリタは、第一層をコンパイルするために起動することができ、性能監視機能をオンにしません。
層1、また、コンパイルされたC1、ネイティブコードへコンパイルバイトコード、簡単、確実かつ最適化され、必要に応じて、追加パフォーマンスモニタロジックとしても知られています。
レイヤ2、またC2、ネイティブコードへの長いバイトコードコンパイラの最適化にコンパイル、いくつかのコンパイラが有効になっています。
2.2コンパイルされたオブジェクト
2.2.1ホットコード
(1)メソッドが複数回呼び出され、プロセス全体にコンパイルされたオブジェクトとしてコンパイル時間は、標準的な方法JITコンパイラである:ホットコードは、2つのカテゴリを有します
(2)コンパイルされたオブジェクトのメソッドへのループが実行される複数回、ループ本体としてスタックに(OSRコンパイラ)、いわゆる交換はコンパイルプロセスで発生
コードがホットスポットであるかどうかを決定する、2つの方法があります。
(1)ホットスポットを検出するためのサンプリングに基づく仮想機会を定期的にこの方法が頻繁にスタックホットメソッドの先頭に表示される方法であることが判明した場合、各スレッドのスタックの先頭を確認してください。
ホットスポットの(2)カウンタベースの検出:実行カウンタの数を確立するために、仮想マシン、各方法の統計的手法、実行回数が所定の閾値をホット方法をプレイしていると考えられる超える場合。
2.3コンパイルプロセス
2.3.1クライアントコンパイラコンパイラ・プロセス
C1の場合は、コンパイル処理は、3つの段階に分けることができます。
- 第一段階、コード値を表すために、静的単一代入(SSA)を使用して、より高い中間表現(HIR)、HIRを形成するように構成されたプラットフォームに依存しないバイトコードの前端。コンパイラの最適化バイトコードの一部が完了する前にこのような関連する方法、定数伝播最適化など。
- 第二段階は、プラットホームの後端部は、HIRから下部中間表現(LIR)を生成します。このようヌルチェックの排除、のようなクリアとする範囲チェックとして、HIR上のいくつかの他の最適化の前に完了します。
- 最終段階、LIRにリニアスキャンレジスタ割り当てアルゴリズムを使用してバックエンド・プラットホーム、及びLIRにのぞき穴を行うには、その後、マシンコードを生成します。
図クライアントコンパイラを処理します:
2.3.2サーバーコンパイラコンパイラ・プロセス
サーバコンパイラは、具体的には、サーバ側のための典型的なアプリケーションでは、このようなデッドコードのような任意の古典的な最適化操作は、クリアされ、ループアンローリング式は基本ブロックを並べ替え、アウターループ、共通部分式除去、定数伝播を挙げる行います。更なる説明は、ガードインライン、分岐予測の最適化周波数(仮定は、このようなタイプの継承構造の変更など積極的な最適化がない場合、缶としての性能監視情報提供またはクライアントコンパイラ、不安定性のいくつかの積極的な最適化に基づいて行われます)継続して逆最適化状態によって解釈に戻ります。
2.4コンパイラの最適化技術
2.4.1共通部分式除去
Aが算出された発現、およびA内のすべての変数の現在の値に計算し、前からは変更されない場合、Aの出現は、共通部分式となっています。この発現のために、それだけAが直接上記式の結果を用いて算出することができる代わりに、再計算時間を費やす必要がありません。例えば:
INT A = C + B *(3 * B +。C); // 最適化 INT(。+ 3 A = A + A); // 最適化 INT A * A + 2 = 3。
排除をチェック2.4.2配列境界
当访问一个数组的时候,经常会对数组的边界进行检查。而可以采取的优化就是在数据流分析时确定对数组的访问不会超过数组范围就不再每次进行数组越界检查。
2.4.3 方法内联
就是将一些没用的代码剔除,或者对于没有必要的方法跳转,将目标方法中的代码 “复制”到发起调用的方法之中,避免真实的方法调用。因为 Java 中的多态性的存在因此,内联有时不能确定目标方法,对应的情况如下:
如果是非虚方法,直接进行内联。
如果是虚方法,只有一个版本,进行守护内联属于激进优化,要设置”逃生门“,没有变化时继续内联,若是加载了一个有变化的新类就直接抛弃退回解释执行。如果有多个版本,就做内联缓存,在未发生内联的时候,缓存为空,第一次调用方法时,记录方法的调用者,后面每次调用就进行判断,一致就继续进行,不一致就取消内联。
2.4.4 逃逸分析
逃逸分析的基本行为就是分析对象的动态作用域:当一个对象在方法中被定义后可能被外部方法所引用,例如传参,称为方法逃逸。还有被外部线程访问到,例如赋值给类变量,称为线程逃逸。如果一个对象不会逃逸那么可以进行如下优化:
(1)栈上分配:在栈上分配内存,对象所占的内存空间随栈帧出栈而销毁。
(2)同步消除:消除没有必要的线程同步。
(3)标量替换:标量是指一个数据不能再分解,比如原始数据类型(int、long等)。相对的,一个数据可以继续分解,那称它为聚合量,例如对象。如果把一个Java对象拆散,根据程序访问情况,将其使用到的成员变量恢复原始类型来访问,称为标量替换。如果一个对象可以被分解,且不会逃逸,就直接使用标量代替对对象的成员变量,而不直接创建这个对象。