2009-04-21 20 views
35

Por lo que sé, la JVM usa el análisis de escape para obtener un rendimiento optimisations, como bloqueo de engrosamiento y bloqueo de elisión. Me interesa si existe la posibilidad de que la JVM decida que se puede asignar un objeto en particular en la pila mediante el análisis de escape.Análisis de escape en Java

Algunos resources me hacen pensar que tengo razón. ¿Hay JVM que realmente lo hacen?

+3

Documentación de Oracle: después del análisis de escape, el compilador del servidor elimina las asignaciones de objetos escalares reemplazables y los bloqueos asociados del código generado. El compilador del servidor también elimina bloqueos para todos los objetos que no escapan globalmente. NO REEMPLAZA UNA ASIGNACIÓN DE HEAL CON UNA ASIGNACIÓN DE PILA. – anstarovoyt

+0

@anstarovoyt No reemplaza una asignación de pila con una asignación de pila PARA OBJETOS QUE NO ESCAPEN DE FORMA NO GLOBAL. – Aliaxander

+0

@Aliaxander se formuló la pregunta en 2009 y mi respuesta fue en 2013 :) – anstarovoyt

Respuesta

5

No creo que escape el análisis para la asignación de la pila. ejemplo:

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

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

Supuestamente JDK 7 supports stack allocation.

+0

Aquí está el enlace para los documentos en Java 7: http: // docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis – robinst

+1

Creo que estás equivocado. No tienes una fase de calentamiento aquí. mira esta publicación - https://minborgsjavapot.blogspot.co.il/2015/12/do-not-let-your-java-objects-escape.html –

90

Con esta versión de java -XX: + DoEscapeAnalysis da como resultado mucha menos actividad de gc y una ejecución 14 veces más rápida.

$ 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 

Sin un análisis escape,

$ 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 

Con el análisis de escape,

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

La ejecución en tiempo reduce significativamente con el análisis de escape. Para ello, el bucle se cambió a iteraciones 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); 
} 

Sin un análisis de escape,

$ time java -server EscapeAnalysis 
start 
1000000000 

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

Con el análisis de escape,

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

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

Así que con el análisis de escape el ejemplo corrió sobre 14 veces más rápido que el análisis de no escape se ejecuta.

+2

Si ejecutas "java -server" entonces deberías usar "java" -servidor -version "para ver su versión, no solo" java -version ". – Oak

+13

Esto funciona genial. Debe ser la respuesta aceptada – HRJ

+1

Consulte también la documentación de Java 7 al respecto: http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#escapeAnalysis – robinst

2

El análisis de escape es muy bueno, pero no es una obtención completa de la tarjeta libre de la cárcel. si tiene una colección de tamaño dinámico dentro de un objeto, el análisis de escape NO cambiará de pila a pila. Por ejemplo:

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

Incluso si se crea este objeto en un método y absolutamente no escapa desde un punto de vista sintáctico, el compilador no marcar este para escapar. Sospecho que debido a que longList no está realmente limitado en tamaño desde una perspectiva sintáctica pura y podría explotar tu pila potencialmente. Por lo tanto, creo que se necesita un pase en este caso. Experimenté con esto donde el longList estaba vacío y todavía causó colecciones en un micro benchmark simple.

+0

Eso es porque 'longList' está asignado en el constructor' toEscape's. El constructor parece no estar en línea, por lo que la referencia 'longList' escapa. El tipo del objeto no importa en este caso. –

Cuestiones relacionadas