38

As far as I know the JVM uses escape analysis for some performance optimisations like lock coarsening and lock elision. I'm interested if there is a possibility for the JVM to decide that any particular object can be allocated on stack using escape analysis.

Some resources make me think that I am right. Is there JVMs that actually do it?

Björn Lindqvist
  • 19,221
  • 20
  • 87
  • 122
Denis Bazhenov
  • 9,680
  • 8
  • 43
  • 65
  • 4
    Oracle documentation: After escape analysis, the server compiler eliminates scalar replaceable object allocations and associated locks from generated code. The server compiler also eliminates locks for all non-globally escaping objects. IT DOES NOT REPLACE A HEAP ALLOCATION WITH A STACK ALLOCATION. – anstarovoyt Apr 03 '13 at 19:57
  • @anstarovoyt It does not replace a heap allocation with a stack allocation FOR NON-GLOBALLY ESCAPING OBJECTS. – Aliaxander Sep 13 '16 at 09:00
  • @Aliaxander the question was asked in 2009 and my answer was in 2013 :) – anstarovoyt Sep 13 '16 at 09:14
  • 1
    @anstarovoyt let the comment be just in case in order to prevent confusion considering newer JDK releases. – Aliaxander Sep 13 '16 at 10:10

3 Answers3

94

With this version of java -XX:+DoEscapeAnalysis results in far less gc activity and 14x faster execution.

$ 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

Without escape analysis,

$ 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

With escape analysis,

$ java -server -verbose:gc -XX:+DoEscapeAnalysis EscapeAnalysis
start
[GC 896K->102K(5056K), 0.0055600 secs]
10000000

The execution time reduces significantly with escape analysis. For this the loop was changed to 10e9 iterations,

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);
}

Without escape analysis,

$ time java -server EscapeAnalysis
start
1000000000

real    0m27.386s
user    0m24.950s
sys     0m1.076s

With escape analysis,

$ time java -server -XX:+DoEscapeAnalysis EscapeAnalysis
start
1000000000

real    0m2.018s
user    0m2.004s
sys     0m0.012s

So with escape analysis the example ran about 14x faster than the non-escape analysis run.

Janek Bogucki
  • 5,033
  • 3
  • 30
  • 40
  • 2
    If you run "java -server" then you should use "java -server -version" to see its version, not just "java -version". – Oak May 09 '10 at 13:21
  • 1
    See also the Java 7 documentation about it: http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis – robinst Aug 12 '14 at 11:24
  • http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis – Ahmed Hegazy Jan 02 '16 at 21:39
  • I ran this under jdk1.8.0_05 and it behaves like escape analysis is enabled by default – lcfd Mar 01 '16 at 15:52
  • 3
    The documentation notes that escape analysis is now on by default: https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html. _-XX:+DoEscapeAnalysis Enables the use of escape analysis. This option is enabled by default. To disable the use of escape analysis, specify -XX:-DoEscapeAnalysis. Only the Java HotSpot Server VM supports this option._ – Janek Bogucki Mar 01 '16 at 16:51
  • 1
    You can also list the settings directly with `java -XX:+PrintFlagsFinal 2>&1|grep EscapeAnalysis` – Janek Bogucki Mar 01 '16 at 16:53
  • [Escape Analysis is on by default since Java SE 6u23](http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis), so this answer using Java SE 6u14 was made shortly before it became the default. – Holger Jun 19 '17 at 12:47
4

I don't think it does escape analysis for stack allocation. example:

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);
    }
}

with -server -verbose:gc -XX+DoEscapeAnalysis:

start
[GC 3072K->285K(32640K), 0.0065187 secs]
[GC 3357K->285K(35712K), 0.0053043 secs]
[GC 6429K->301K(35712K), 0.0030797 secs]
[GC 6445K->285K(41856K), 0.0033648 secs]
[GC 12573K->285K(41856K), 0.0050432 secs]
[GC 12573K->301K(53952K), 0.0043682 secs]
[GC 24877K->277K(53952K), 0.0031890 secs]
[GC 24853K->277K(78528K), 0.0005293 secs]
[GC 49365K->277K(78592K), 0.0006699 secs]
10000000

Allegedly JDK 7 supports stack allocation.

Nayuki
  • 17,911
  • 6
  • 53
  • 80
benmmurphy
  • 2,503
  • 1
  • 20
  • 30
  • Here's the link for the docs in Java 7: http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis – robinst Aug 12 '14 at 11:23
  • 1
    i think you are wrong.you dont have a warmup phase here. see this post - https://minborgsjavapot.blogspot.co.il/2015/12/do-not-let-your-java-objects-escape.html – Avihai Marchiano Sep 04 '16 at 18:14
2

Escape analysis is really nice, but it is not a complete get of jail free card. if you have a dynamically sized collection inside of an object, the escape analysis will NOT switch from heap to stack. For example:

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

Even if this object is created in a method and absolutely does NOT escape from a syntactic point of view, the compiler will not mark this for escape. I suspect because that longList is not really bounded in size from a pure syntactic perspective and it could blow your stack potentially. Thus I believe it takes a pass on this case. I experimented with this where the longList was empty and still it caused collections in a simple micro benchmark.

  • That's because `longList` is allocated in `toEscape`s constructor. The constructor seem not to be inlined, so the `longList` reference therefore escapes. The type of the object does not matter in this case. – Björn Lindqvist Oct 12 '17 at 21:25