私の知る限り、JVMはいくつかのパフォーマンスのためにエスケープ分析を使用しています 最適化 ロックの粗大化やロックの省略など。エスケープ分析を使用して、JVMが特定のオブジェクトをスタックに割り当てることができると判断する可能性があるかどうかに興味があります。
いくつか resources 私は正しいと思わせます。実際にそれを行うJVMはありますか?
スタック割り当てのエスケープ分析は行わないと思います。例:
public class EscapeAnalysis {
private static class Foo {
private int x;
private static int counter;
public Foo() {
x = (++counter);
}
}
public static void main(String[] args) {
System.out.println("start");
for (int i = 0; i < 10000000; ++i) {
Foo foo = new Foo();
}
System.out.println(Foo.counter);
}
}
-server -verbose:gc -XX+DoEscapeAnalysis
:
start [GC 3072K-> 285K(32640K)、0.0065187秒] [GC3357K-> 285K(35712K)、0.0053043秒] [GC6429K -> 301K(35712K)、0.0030797秒] [GC6445K-> 285K(41856K)、0.0033648秒] [GC12573K-> 285K(41856K)、0.0050432秒] [GC 12573K-> 301K(53952K)、0.0043682秒] [GC24877K-> 277K(53952K)、0.0031890秒] [GC24853K-> 277K(78528K)、0.0005293秒] [GC 49365K-> 277K(78592K)、0.0006699秒] 10000000
伝えられるところでは JDK 7はスタック割り当てをサポートします 。
このバージョンのJava -XX:+ DoEscapeAnalysisを使用すると、gcアクティビティがはるかに少なくなり、実行が14倍速くなります。
$ Java -version
Java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) Client VM (build 14.0-b16, mixed mode, sharing)
$ uname -a
Linux xxx 2.6.18-4-686 #1 SMP Mon Mar 26 17:17:36 UTC 2007 i686 GNU/Linux
エスケープ分析なしで、
$ Java -server -verbose:gc EscapeAnalysis|cat -n
1 start
2 [GC 896K->102K(5056K), 0.0053480 secs]
3 [GC 998K->102K(5056K), 0.0012930 secs]
4 [GC 998K->102K(5056K), 0.0006930 secs]
--snip--
174 [GC 998K->102K(5056K), 0.0001960 secs]
175 [GC 998K->102K(5056K), 0.0002150 secs]
176 10000000
エスケープ分析では、
$ Java -server -verbose:gc -XX:+DoEscapeAnalysis EscapeAnalysis
start
[GC 896K->102K(5056K), 0.0055600 secs]
10000000
エスケープ分析により、実行時間が大幅に短縮されます。このため、ループは10e9回の反復に変更されました。
public static void main(String [] args){
System.out.println("start");
for(int i = 0; i < 1000*1000*1000; ++i){
Foo foo = new Foo();
}
System.out.println(Foo.counter);
}
エスケープ分析なしで、
$ time Java -server EscapeAnalysis
start
1000000000
real 0m27.386s
user 0m24.950s
sys 0m1.076s
エスケープ分析では、
$ time Java -server -XX:+DoEscapeAnalysis EscapeAnalysis
start
1000000000
real 0m2.018s
user 0m2.004s
sys 0m0.012s
したがって、エスケープ分析では、この例は非エスケープ分析の実行よりも約14倍速く実行されました。
エスケープ分析は本当に素晴らしいですが、それはジェイルフリーカードの完全な入手ではありません。オブジェクト内に動的なサイズのコレクションがある場合、エスケープ分析はヒープからスタックに切り替わりません。例えば:
public class toEscape {
public long l;
public List<Long> longList = new ArrayList<Long>();
}
このオブジェクトがメソッドで作成され、構文の観点から絶対にエスケープしない場合でも、コンパイラーはこれにエスケープのマークを付けません。 longListは、純粋な構文の観点からはサイズが実際には制限されておらず、スタックを破壊する可能性があるためだと思います。したがって、私はそれがこの場合に合格すると信じています。 longListが空であるにもかかわらず、単純なマイクロベンチマークでコレクションが発生するという実験を行いました。