web-dev-qa-db-ja.com

Javaのエスケープ分析

私の知る限り、JVMはいくつかのパフォーマンスのためにエスケープ分析を使用しています 最適化 ロックの粗大化やロックの省略など。エスケープ分析を使用して、JVMが特定のオブジェクトをスタックに割り当てることができると判断する可能性があるかどうかに興味があります。

いくつか resources 私は正しいと思わせます。実際にそれを行うJVMはありますか?

37
Denis Bazhenov

スタック割り当てのエスケープ分析は行わないと思います。例:

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はスタック割り当てをサポートします

5
benmmurphy

このバージョンの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倍速く実行されました。

92
Janek Bogucki

エスケープ分析は本当に素晴らしいですが、それはジェイルフリーカードの完全な入手ではありません。オブジェクト内に動的なサイズのコレクションがある場合、エスケープ分析はヒープからスタックに切り替わりません。例えば:

public class toEscape {
   public long l;
   public List<Long> longList = new ArrayList<Long>();
}

このオブジェクトがメソッドで作成され、構文の観点から絶対にエスケープしない場合でも、コンパイラーはこれにエスケープのマークを付けません。 longListは、純粋な構文の観点からはサイズが実際には制限されておらず、スタックを破壊する可能性があるためだと思います。したがって、私はそれがこの場合に合格すると信じています。 longListが空であるにもかかわらず、単純なマイクロベンチマークでコレクションが発生するという実験を行いました。

2
Mike Ceruti