2009-04-21 7 views
35

Autant que je sache, la JVM utilise l'analyse d'échappement pour certaines performances optimisations comme le verrouillage de verrouillage et l'élision de verrouillage. Je suis intéressé s'il y a une possibilité pour la JVM de décider qu'un objet particulier peut être alloué sur la pile en utilisant l'analyse d'échappement.Analyse d'échappement en Java

Certains resources me font penser que j'ai raison. Y a-t-il des JVM qui le font réellement?

+3

Documentation d'Oracle: Après l'analyse d'échappement, le compilateur de serveur élimine des allocations remplaçables scalaires d'objet et des verrous associés du code produit. Le compilateur de serveur élimine également les verrous pour tous les objets échappant à la globalité. IL NE REMPLACE PAS UNE ALLOCATION HEAP AVEC UNE ALLOCATION DE STACK. – anstarovoyt

+0

@anstarovoyt Il ne remplace pas une allocation de tas avec une allocation de pile POUR DES OBJETS NON GLOBALEMENT ÉCHAPPÉS. – Aliaxander

+0

@Aliaxander la question a été posée en 2009 et ma réponse a été en 2013 :) – anstarovoyt

Répondre

5

Je ne pense pas que cela échappe à l'analyse pour l'allocation de pile. exemple:

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

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

Prétendument JDK 7 supports stack allocation.

+0

Voici le lien pour les docs en Java 7: http: // docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis – robinst

+1

Je pense que vous avez tort. Vous n'avez pas de phase de réchauffement ici. voir ce post - https://minborgsjavapot.blogspot.co.il/2015/12/do-not-let-your-java-objects-escape.html –

90

Avec cette version de java -XX: + DoEscapeAnalysis se traduit par beaucoup moins d'activité gc et une exécution 14 fois plus rapide.

$ 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 

Sans l'analyse d'échappement,

$ 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 

Avec l'analyse d'échappement,

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

Le temps d'exécution réduit de manière significative avec l'analyse d'échappement. Pour cela, la boucle a été changé pour les itérations de 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); 
} 

Sans l'analyse d'échappement,

$ time java -server EscapeAnalysis 
start 
1000000000 

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

Avec l'analyse d'échappement,

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

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

Donc, avec l'analyse d'échappement l'exemple courait 14x plus vite que l'analyse non-échappée.

+2

Si vous exécutez "java -server" alors vous devriez utiliser "java" -server -version "pour voir sa version, pas seulement" java -version ". – Oak

+13

Cela fonctionne très bien. Devrait être la réponse acceptée – HRJ

+1

Voir aussi la documentation de Java 7 à ce sujet: http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis – robinst

2

L'analyse d'échappement est vraiment sympa, mais ce n'est pas une carte complète de prison. Si vous avez une collection de taille dynamique à l'intérieur d'un objet, l'analyse d'échappement ne passera PAS de tas à pile. Par exemple:

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

Même si cet objet est créé dans une méthode et ne absolument échappe pas d'un point de vue syntaxique, le compilateur ne marquera pas cela pour échapper. Je suppose que cette liste n'est pas vraiment limitée en taille d'un point de vue purement syntaxique et qu'elle pourrait potentiellement faire exploser votre pile. Ainsi, je crois qu'il faut une passe sur cette affaire. J'ai expérimenté avec ceci où le longList était vide et encore il a provoqué des collections dans un micro benchmark simple

+0

C'est parce que 'longList' est alloué dans le constructeur' toEscape'. Le constructeur ne semble pas être en ligne, donc la référence 'longList' s'échappe donc. Le type de l'objet n'a pas d'importance dans ce cas. –