私たちはコードを書くときに、行の数は、自然法の内部が優れているので、ロジックが明確である、読みやすい、それよりも実際には、メリットははるかに、時間のコンパイルによって、あるいは実行は、今日、私たちは見てみましょうするときのパフォーマンスを向上させますそれの原則を見てみましょう。
簡単な紹介
JVMの初期化が完了すると、オペレーティング・システムで実行する前に、実行中のクラス呼び出し、実行エンジンは、マシンコードにコードをバイトになります。仮想マシン、プロセス中にマシンコードにバイトコードを変換し、コンパイラがまだある、それはあります即时编译
。
仮想マシンは、これらのコードとして識別される場合に特に頻繁に実行するメソッドまたはコードのブロックを発見したとき、最初に、バイトコードインタプリタ(インタプリタ)によってJVMは、コンパイルします热点代码
。
実行時にホットコードの効率を改善するために、リアルタイムのコンパイラ(時間だけでJITは、)機械ネイティブプラットフォームに関連付けられたコード、および最適化のすべてのレベルにコードをコンパイルし、その後メモリに保存しました。
分類
HotSpot仮想マシンでは、それはそれぞれ、2つのJITを建て、C1 编译器
そしてC2 编译器
両方のコンパイラが同じではない、コンパイルプロセスを。
C1コンパイラ
C1コンパイラは、シンプルで早いのが特長コンパイラで、主な焦点としても知られる、短い実行時間やプログラムの開始の性能要件のために最適化されたローカライズされてClient Compiler
、例えば、GUIアプリケーションがあり、発射速度をインタフェースします一定の要件。
C2コンパイラ
C2コンパイラはまたとして知られている長い時間のためか、ピーク性能要件のためのプログラムの実施のための長時間実行サーバー側のアプリケーションコンパイラのためのパフォーマンスチューニングを行っているServer Compiler
、例えば、Javaアプリケーションは、長期安定性のためにサーバー上で実行されています実行するための一定の要件があります。
階層のコンパイル
対応するJITを選択する必要がJava7、前に、プログラムは、特性に応じて、前記協働するデフォルトの仮想マシンインタプリタおよびコンパイラを使用。
Java7は、階層型コンパイルを導入し、このアプローチは、C1とC2のパフォーマンスと最高のパフォーマンス上の利点を開始することの利点は、我々はまた、パラメータを渡すことができ兼ね備え-client
または-server
仮想マシンのタイムコンパイル・モードを強制します。
JVMのコンパイルは、階層的な状態が5つのレベルに分かれて行います。
レイヤー0:あなたは、電源を入れていない第二層コンパイルをトリガーする可能性がある場合の実装を説明するためのプログラムは、パフォーマンスの監視は、デフォルト(プロファイリング)で有効になっています。
層1:C1は、コンパイルと呼ばれるネイティブコードへのバイトコードをコンパイルし、簡単、確実かつ最適化することができる、プロファイルを開けません。
層2:また、コンパイルされたC1呼ばれ、プロファイリングは、呼び出しメソッドで実行され、コンパイルされた実行時間をプロファイリングC1側に再循環の数のみを開きました。
レイヤ3:また、C1コンパイラと呼ばれる、コンパイラは、テープのすべてC1プロファイリングを実行します。
レイヤ4:C2は、バイトコードをコンパイルするために呼ばれることもあるがネイティブコードにコンパイルされていますが、いくつかの長いコンパイルの最適化、さらにいくつかの信頼性の低いラジカル最適化パフォーマンス監視情報を有効にします。
三つの状態C1は、ハイからローへの効率に応じて第一層、第二層、第三層。
通常、C2はC1の30%以上の効率よりも高くなります。
Java8では、デフォルト階層コンパイルで有効になって、-client
そして-server
設定が無効アップされています。あなたはC2を開きたい場合は、(階層的なコンパイルを閉鎖することができる-XX:-TieredCompilation
)成層パラメータをコンパイルしながら、唯一の彼らのC1により、開くことができます:-XX:TieredStopAtLevel=1
。
あなたはできるjava -version
コンパイラで使用される現在のシステムに直接コマンドラインモードを表示することができます。
C:\Users\Administrator>java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
mixed mode
ミックスを代表して、このモデルに加えて、我々はまた、使用することができ、デフォルトのコンパイル・モードで-Xint
のみ、JITは、その後、完全に仕事に関与コンパイルモードのインタプリタ下で実行する仮想マシンを強制的にパラメータを、あなたはパラメータを使用することができ-Xcomp
、仮想マシンが実行のみ強制的にJITコンパイルモードで。例えば:
C:\Users\Administrator>java -Xint -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, interpreted mode)
C:\Users\Administrator>java -Xcomp -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, compiled mode)
トリガ基準
HotSpot仮想マシンでは、热点探测
それはJITのトリガ基準です。
ホットスポット検出はホットカウンタの検出に基づいており、このアプローチの仮想機会が実行回数は、それが考えられている一定の閾値を超えた場合には、各メソッドの実行統計カウンターの数を確立することである「ホットスポット方法を。」
仮想マシンの二種類の各メソッドのために対抗する準備ができている:メソッド呼び出しカウンタ(呼び出しカウンタ)とカウンターの裏側(バックエッジカウンタ)。カウンタが閾値オーバーフローを超えた場合に、決定された閾値を有するこれら二つのカウンタの前提の下で実行している仮想マシンのパラメータを決定するには、JITコンパイラをトリガします。
メソッド呼び出しカウンタ
この方法は、カウンタの周波数を求め、統計メソッドが呼び出され、デフォルトのしきい値モード1500モードC1、C2で10,000倍である、ことができる-XX: CompileThreshold
設定され、階層化コンパイル済みの場合には-XX: CompileThreshold
指定されたしきい値失敗し、この時点では、動的にコンパイルされたスレッドの数をコンパイルする現在の方法の数に応じて調整されます。場合メソッドカウンタと、カウンタの後ろ側とカウンタ閾値法上には、JITコンパイラをトリガします。
裏面カウンター
裏面カウンタトリガC1をコンパイルするかどうかを計算するために使用されるバイトコード値の「裏側」(後縁)と呼ばれるジャンプ命令の後に、回数を制御フロー遭遇をループ処理コードの実行をカウント閾値は、コンパイルされた階層、C1デフォルト13995を開くことなく、C2のデフォルト10700ができます-XX: OnStackReplacePercentage=N
設定することが、階層化コンパイル済みの場合には-XX: OnStackReplacePercentage
指定されたしきい値にも失敗し、その後電流があろうコンパイルされたメソッドの数と動的コンパイラを調整するスレッドの数。
(StackReplacementオン)OSRコンパイルにコンパイラスタックをトリガするために確立カウンタの裏側の主な目的。いくつかの比較的長い周期のコードセグメントでは、カウンタのループバック側が閾値に達したときに、JVMは、このコードがホットだと思うであろう、JITコンパイラは周期で、機械語コードとキャッシュにコンパイルされます内部に、それが直接機械語のキャッシュを実行し、コードが実行されます置き換えられます。
最適化技術
JITコンパイラは、操作のうち最適なパフォーマンスのためにルーチンチェックの最適化、インテリジェントにコンパイルされたコードの数を介して、つまり、コードを達成するために、古典的なコンパイラ最適化技術の一部の使用を最適化します。2があり方法内联
、メインは:逃逸分析
、。
インラインメソッド
プッシュとポップを通過する通常メソッドを呼び出します。メソッド呼び出しは、実行メソッドの前の位置に戻り、その後、方法のコンテキストを実行メモリアドレスに格納されたプログラムの実行順序に転送されます。
これは、操作を継続するために、以前に保存したアドレスに応じて、実行サイトの後に復元することが、実行サイトと実行メモリアドレスの前に主張し実行します。したがって、メソッドの呼び出しは、いくつかのオーバーヘッド時間と空間(実際には、として理解することができる生成する上下文切换
剥離ダウンバージョン)。
だから、それらのボディコードの非常に大きな、だけでなく、頻繁にメソッドと呼ばないで、この時間と空間の消費は素晴らしいものです。
行動インライン方式の最適化メソッド呼び出しを開始したターゲットプロセスにコードをコピーすることで、この方法は、実際の発生を回避するために呼び出します。
自動的にホットスポットのJVM方法を特定し、それらが同時最適化の方法が提供されます。私たちはできる-XX:CompileThreshold
しきい値ホットスポットアプローチを設定します。あまりにメソッド本体た場合でも、フォーカス方式は、必ずしもでは、最適化されたJVMに行われないことを強調するために、JVMはインライン操作を実行しません。メソッド本体のサイズのしきい値、我々はパラメータを設定することで、最適化することができます。
- 頻繁に実行されるメソッドは、デフォルトでは、より少ない325バイトのメソッド本体のサイズがインラインされ、我々ができ
-XX:MaxFreqInlineSize=N
サイズ値を設定します。 - この方法は、多くの場合、デフォルトでは、実行されていない、未満35バイトの方法サイズはインラインになり、私たちもできる
-XX:MaxInlineSize=N
大きさの値をリセットします。
その後、我々が見ることができる状況にはJVMパラメータを設定することにより、インライン方法は次のとおりです。
// 在控制台打印编译过程信息
-XX:+PrintCompilation
// 解锁对 JVM 进行诊断的选项参数。默认是关闭的,开启后支持一些特定参数对 JVM 进行诊断
-XX:+UnlockDiagnosticVMOptions
// 将内联方法打印出来
-XX:+PrintInlining
ホット最適化の方法が効果的にシステムのパフォーマンスを向上させることができ、我々は一般的に以下の方法の方法で改善することができます。
- ホットスポットを低減するために閾値を設定以上のメソッドをインライン化することができるが、この方法は、より多くのメモリを占有する必要性を意味するように、その閾値を増加させることによってJVMパラメータ。
- プログラミングでは、方法は、小さな体を使用するために使用する方法に多くのコードを書くことを避けます。
- 相続として符号化方法、最終的に、プライベート、静的なキーワードの変更方法を使用してみてください、それは追加の型チェックが必要になります。
ここでは、方法は、多くの場合、インラインメソッドを実行する方法の内容以下は、パフォーマンスを最適化するのは簡単です、最初に提唱ビューにリンクされています。
エスケープ解析
分析エスケープ(分析エスケープ)オブジェクトを解析する方法でアクセスするスレッドの外側または外部参照されているかどうかを決定することで、コンパイラは、エスケープ解析の結果に応じてコードを最適化することができます。
JVMパラメータは、によって設定することができます。
-XX:+DoEscapeAnalysis 开启逃逸分析(jdk1.8 默认开启)
-XX:-DoEscapeAnalysis 关闭逃逸分析
具体的な最適化の方法があります栈上分配
3: 、、。锁消除
标量替换
スタックに割り当て
Javaでオブジェクトを作成し、デフォルトはメモリのヒープ割り当てでオブジェクトを作成し、破壊することである、とヒープオブジェクトが使用されなくなったとき、あなたはガベージコレクション機構に必要としない、このプロセスは話すのスタック内の比較的割り当てです時間がかかり、パフォーマンスとより。
オブジェクトが唯一の方法では、オブジェクトがスタックに割り当てられます発見された場合は、この時間は、分析を逃れます。
ただし、データは私がJava8に表示され表示されません(現在の実装のHotSpot仮想マシンは、それは、この最適化のHotSpotのない実現はありません、と言うことができるスタックに割り当てるためのより複雑な先導を達成するために私たちは、この最適化を理解するために一時的にできないことがありますあなたが他の発見、ウェルカムメッセージ)を持っている場合、実現しています。
ロック排除
今回のJITコンパイラはロックが解消ロックこの方法に反対するだろう、あなたはシングルスレッド環境である場合は、実際には、スレッドセーフなコンテナを使用する必要はありませんが、ないスレッドの競合が生じないためにも、使用していました。例えば:
public static String getString(String s1, String s2) {
StringBuffer sb = new StringBuffer();
sb.append(s1);
sb.append(s2);
return sb.toString();
}
JVMパラメータは、によって設定することができます。
-XX:+EliminateLocks 开启锁消除(jdk1.8 默认开启)
-XX:-EliminateLocks 关闭锁消除
スカラー交換
エスケープ解析は、プログラムの実際の実装は、オブジェクトを作成し、代わりに変数を作成し、そのメンバーを指示しない場合がありますとき、このオブジェクトは、その後、分割することができる場合は、オブジェクトは、外部からのアクセスではないことを証明しました。オブジェクトを分割した後、オブジェクトメンバ変数は、スタックまたはレジスタに割り当てることができ、元のオブジェクトはメモリ空間アップを割り当てる必要はありません。このコンパイラの最適化は、スカラー交換と呼ばれます。
例えば:
public void foo() {
TestInfo info = new TestInfo();
info.id = 1;
info.count = 99;
// to do something
}
エスケープ分析した後、最適化されたコードは次のようになります。
public void foo() {
id = 1;
count = 99;
// to do something
}
JVMパラメータは、によって設定することができます。
-XX:+EliminateAllocations 开启标量替换(jdk1.8 默认开启)
-XX:-EliminateAllocations 关闭就可以了
概要
今日の内容は、最も基本的な常識から方法内部行数和逻辑需要尽可能简单
リード、プロセスを理解することは、ホットコードのJVM時のコンパイルで最適化されています。あなたが任意のアイデアを持っている場合は、コメントは以下の歓迎されています。
私のブログをご覧いただくか、私に公共の数、見出し番号を追跡することができます興味を持っている、多分驚きがあるでしょう。