Java中的逃逸分析

据我所知,JVM使用逃逸分析进行一些性能优化,比如locking粗化和locking。 我感兴趣的是,如果JVM有可能决定使用转义分析可以在堆栈上分配任何特定的对象。

有些资源让我觉得我是对的。 有没有实际上这样做的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

开始
 [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秒]
千万

据称JDK 7支持堆栈分配 。

使用这个版本的java -XX:+ DoEscapeAnalysis会导致gc活动less得多,执行速度快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 

执行时间显着减less逃逸分析。 为此循环被改为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倍。

逃生分析真的很好,但它不是一个完整的监狱免费卡。 如果在一个对象内部有一个dynamic大小的集合,则转义分析不会从堆切换到堆栈。 例如:

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

即使这个对象是在一个方法中创build的,绝对不会从语法的angular度转义,编译器不会将其标记为转义。 我怀疑这是因为longList的大小并不是纯粹的语法范围,它可能会打击你的堆栈。 因此,我认为这个案件需要通过。 我尝试了这一点,longList是空的,仍然在一个简单的微基准引起collections。