Анализ побега в Java - PullRequest
       89

Анализ побега в Java

37 голосов
/ 21 апреля 2009

Насколько я знаю, JVM использует анализ выхода для некоторой производительности оптимизаций , таких как укрупнение блокировки и устранение блокировки. Мне интересно, есть ли у JVM возможность решить, что любой конкретный объект может быть размещен в стеке с помощью escape-анализа.

Некоторые ресурсы заставляют меня думать, что я прав. Есть ли JVM, которые действительно это делают?

Ответы [ 3 ]

92 голосов
/ 31 июля 2009

С этой версией 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

Время выполнения значительно сокращается благодаря анализу escape. Для этого цикл был изменен на 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 раз быстрее, чем анализ без побега.

5 голосов
/ 21 апреля 2009

Я не думаю, что он избегает анализа для распределения стека. Пример:

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 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

Предположительно JDK 7 поддерживает выделение стека .

2 голосов
/ 02 декабря 2015

Анализ побега действительно хорош, но он не является полной картой без тюремного заключения. Если у вас есть динамически изменяемая коллекция внутри объекта, анализ escape НЕ переключается с кучи на стек. Например:

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

Даже если этот объект создан в методе и абсолютно НЕ сбегает с синтаксической точки зрения, компилятор не пометит это как escape. Я подозреваю, потому что этот longList на самом деле не ограничен по размеру с чисто синтаксической точки зрения и потенциально может взорвать ваш стек. Таким образом, я считаю, что это дело проходит. Я экспериментировал с этим, когда longList был пуст, и все же он вызывал коллекции в простом микро-тесте.

...