Escape анализ в Java

Доколкото знам, JVM използва escape анализ за някои оптимизации като загрубяване на заключване и изпадане на заключване. Интересувам се дали има възможност JVM да реши, че всеки конкретен обект може да бъде разпределен в стека с помощта на escape анализ.

Някои ресурси ме карат да мисля, че съм прав. Има ли JVM, които всъщност го правят?


person Denis Bazhenov    schedule 21.04.2009    source източник
comment
Документация на Oracle: След анализ на изхода, компилаторът на сървъра елиминира разпределенията на скаларни заменими обекти и свързаните заключвания от генерирания код. Компилаторът на сървъра също елиминира заключванията за всички неглобално екраниращи обекти. ТОЙ НЕ ЗАМЕНЯ РАЗПРЕДЕЛЕНИЕТО НА ХИП С РАЗПРЕДЕЛЯНЕ НА СТЕК.   -  person anstarovoyt    schedule 03.04.2013
comment
@anstarovoyt Не замества разпределението на купчина с разпределение на стека ЗА НЕГЛОБАЛНИ ОБЕКТИ, ИЗБЯГВАЩИ.   -  person Aliaxander    schedule 13.09.2016
comment
@Aliaxander въпросът беше зададен през 2009 г., а моят отговор беше през 2013 г. :)   -  person anstarovoyt    schedule 13.09.2016
comment
@anstarovoyt нека коментарът е за всеки случай, за да се предотврати объркване, като се има предвид по-новите версии на JDK.   -  person Aliaxander    schedule 13.09.2016


Отговори (3)


Не мисля, че избягва анализа за разпределение на стека. пример:

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 поддържа разпределение на стека.

person benmmurphy    schedule 21.04.2009
comment
Ето връзката към документите в Java 7: docs.oracle.com/javase/7/docs/technotes/guides/vm/ - person robinst; 12.08.2014
comment
Мисля, че грешите. Тук нямате фаза на загряване. вижте тази публикация - minborgsjavapot. blogspot.co.il/2015/12/ - person Avihai Marchiano; 04.09.2016

С тази версия на 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 пъти по-бързо от изпълнението на анализа без излизане.

person Janek Bogucki    schedule 31.07.2009
comment
Ако стартирате java -server, тогава трябва да използвате java -server -version, за да видите неговата версия, а не само java -version. - person Oak; 09.05.2010
comment
Вижте също документацията на Java 7 за това: docs.oracle.com/javase/7/docs/technotes/guides/vm/ - person robinst; 12.08.2014
comment
docs.oracle.com/ javase/7/docs/technotes/guides/vm/ - person Ahmed Hegazy; 03.01.2016
comment
Стартирах това под jdk1.8.0_05 и се държи така, сякаш анализът на изхода е активиран по подразбиране - person lcfd; 01.03.2016
comment
В документацията се отбелязва, че escape анализът вече е включен по подразбиране: docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html. -XX:+DoEscapeAnalysis Разрешава използването на escape анализ. Тази опция е активирана по подразбиране. За да деактивирате използването на escape анализ, укажете -XX:-DoEscapeAnalysis. Само Java HotSpot Server VM поддържа тази опция. - person Janek Bogucki; 01.03.2016
comment
Можете също да посочите настройките директно с java -XX:+PrintFlagsFinal 2>&1|grep EscapeAnalysis - person Janek Bogucki; 01.03.2016
comment
Escape Analysis е включен по подразбиране от Java SE 6u23, така че този отговор с помощта на Java SE 6u14 е направен малко преди да стане стандартен. - person Holger; 19.06.2017

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

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

Дори ако този обект е създаден в метод и абсолютно НЕ излиза от синтактична гледна точка, компилаторът няма да маркира това за избягване. Подозирам, защото този longList не е наистина ограничен по размер от чиста синтактична гледна точка и може потенциално да взриви стека ви. Затова вярвам, че трябва да се премине към този случай. Експериментирах с това, където longList беше празен и въпреки това предизвика колекции в обикновен микро бенчмарк.

person Mike Ceruti    schedule 02.12.2015
comment
Това е така, защото longList е разпределено в конструктора toEscapes. Конструкторът изглежда не е вграден, така че препратката longList следователно избягва. Видът на обекта в този случай няма значение. - person Björn Lindqvist; 13.10.2017