javaの脱出分析を深く理解する。
逃亡分析
Javaコードの実行時、JVMパラメータにより、エスケープ解析を開始するかどうかを指定できます。
作用
逃避分析を使って、コンパイラはコードを次のように最適化できます。
ロック解除
一つのオブジェクトが一つのスレッドからしかアクセスできないと発見された場合、このオブジェクトの動作は同期を考慮しなくてもよい。
ロック解除前
オブジェクトまたはスカラを分離して置換します。あるオブジェクトは、連続したメモリ構造として存在する必要がなくてもアクセスできる場合があり、対象の部分(または全部)はメモリではなく、CPUレジスタに記憶されてもよい。
スカラー置換前
Java仮想マシンでは、オブジェクトはJavaスタックにメモリを割り当てることが一般的な常識です。しかし、ある特殊な事情があって、もし逃亡分析を経て、一つの対象が逃げ出していないと発見されたら、スタック上の割り当てに最適化されるかもしれません。これでメモリを積み上げる必要がなくなり、ゴミの回収も不要になります。
脱出分析を開けていない
脱出分析を開く
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。
public static StringBuffer craeteStringBuffer(String s1, String s2) {
StringBuffer sb = new StringBuffer();
sb.append(s1);
sb.append(s2);
return sb;
}
public static String createStringBuffer(String s1, String s2) {
StringBuffer sb = new StringBuffer();
sb.append(s1);
sb.append(s2);
return sb.toString();
}
第一段コードのsbは逃げましたが、第二段コードのsbは逃げませんでした。Javaコードの実行時、JVMパラメータにより、エスケープ解析を開始するかどうかを指定できます。
,-XX:+DoEscapeAnalysis
:エスケープを閉じるという分析は、jdk 1.7からすでにデフォルトでエスケープ分析を開始しています。クローズする必要があるなら、指定-XX:-DoEscape Analysisが必要です。作用
逃避分析を使って、コンパイラはコードを次のように最適化できます。
ロック解除
一つのオブジェクトが一つのスレッドからしかアクセスできないと発見された場合、このオブジェクトの動作は同期を考慮しなくてもよい。
ロック解除前
public void f() {
Object o = new Object();
synchronized(o) {
System.out.println(o);
}
}
ロック解除後
public void f() {
Object o = new Object();
System.out.println(o);
}
スカラー置換オブジェクトまたはスカラを分離して置換します。あるオブジェクトは、連続したメモリ構造として存在する必要がなくてもアクセスできる場合があり、対象の部分(または全部)はメモリではなく、CPUレジスタに記憶されてもよい。
スカラー置換前
public static void main(String[] args) {
alloc();
}
private static void alloc() {
Point point = new Point(1,2);
System.out.println("point.x="+point.x+"; point.y="+point.y);
}
class Point{
private int x;
private int y;
}
スカラー置換後
private static void alloc() {
int x = 1;
int y = 2;
System.out.println("point.x="+x+"; point.y="+y);
}
スタック上の割り当てJava仮想マシンでは、オブジェクトはJavaスタックにメモリを割り当てることが一般的な常識です。しかし、ある特殊な事情があって、もし逃亡分析を経て、一つの対象が逃げ出していないと発見されたら、スタック上の割り当てに最適化されるかもしれません。これでメモリを積み上げる必要がなくなり、ゴミの回収も不要になります。
public static void main(String[] args) {
long a1 = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
alloc();
}
//
long a2 = System.currentTimeMillis();
System.out.println("cost " + (a2 - a1) + " ms");
// , sleep
try {
Thread.sleep(100000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
private static void alloc() {
User user = new User();
}
static class User {
}
Userオブジェクトはalloc法で定義されているが、方法の外部では彼を引用していない。つまり、この対象はallocの外に逃げないということです。JITの脱出分析を経て、メモリの割り当てを最適化することができます。脱出分析を開けていない
Xmx4G -Xms4G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
結果
➜ ~ jps
2809 StackAllocTest
2810 Jps
➜ ~ jmap -histo 2809
num #instances #bytes class name
----------------------------------------------
1: 524 87282184 [I
2: 1000000 16000000 StackAllocTest$User
3: 6806 2093136 [B
4: 8006 1320872 [C
5: 4188 100512 java.lang.String
6: 581 66304 java.lang.Class
中国共産党は100万元のStocAllocTest$Userの実例を作成しました。脱出分析を開く
-Xmx4G -Xms4G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
結果
➜ ~ jps
709
2858 Launcher
2859 StackAllocTest
2860 Jps
➜ ~ jmap -histo 2859
num #instances #bytes class name
----------------------------------------------
1: 524 101944280 [I
2: 6806 2093136 [B
3: 83619 1337904 StackAllocTest$User
4: 8006 1320872 [C
5: 4188 100512 java.lang.String
6: 581 66304 java.lang.Class
エスケープ分析を開始した後(-XX:+DoEscape Analysis)、ヒープメモリの中には8万余りの-XX:-DoEscapeAnalysis
オブジェクトしかありません。以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。