私の知る限り、JVM はロックの粗大化やロック省略などのパフォーマンスの最適化にエスケープ分析を使用します。エスケープ分析を使用して特定のオブジェクトをスタックに割り当てることができると JVM が判断できる可能性があるかどうかに興味があります。
いくつかのリソースは、私が正しいと思わせるものです。実際にそれを行うJVMはありますか?
私の知る限り、JVM はロックの粗大化やロック省略などのパフォーマンスの最適化にエスケープ分析を使用します。エスケープ分析を使用して特定のオブジェクトをスタックに割り当てることができると JVM が判断できる可能性があるかどうかに興味があります。
いくつかのリソースは、私が正しいと思わせるものです。実際にそれを行うJVMはありますか?
このバージョンの 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 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
:
始める [GC 3072K-> 285K(32640K)、0.0065187秒] [GC 3357K-> 285K(35712K)、0.0053043秒] [GC 6429K-> 301K(35712K)、0.0030797秒] [GC 6445K-> 285K(41856K)、0.0033648秒] [GC 12573K-> 285K(41856K)、0.0050432秒] [GC 12573K-> 301K(53952K)、0.0043682秒] [GC 24877K-> 277K(53952K)、0.0031890秒] [GC 24853K-> 277K(78528K)、0.0005293秒] [GC 49365K-> 277K(78592K)、0.0006699秒] 10000000
伝えられるところでは、JDK7はスタック割り当てをサポートしています。
エスケープ分析は本当に素晴らしいですが、脱獄カードの完全な取得ではありません. オブジェクト内に動的にサイズ設定されたコレクションがある場合、エスケープ分析はヒープからスタックに切り替わりません。例えば:
public class toEscape {
public long l;
public List<Long> longList = new ArrayList<Long>();
}
このオブジェクトがメソッドで作成され、構文の観点から絶対にエスケープしない場合でも、コンパイラはこれをエスケープとしてマークしません。その longList は、純粋な構文の観点からサイズが実際に制限されておらず、スタックを潜在的に破壊する可能性があるためだと思います。したがって、私はそれがこのケースをパスすると信じています。longList が空の場合にこれを試してみましたが、単純なマイクロ ベンチマークでコレクションが発生しました。</p>