2010-03-11 41 views
12

Codificación vine para comprobar el rendimiento vararg de Java.rendimiento varargs de Java

escribo siguiente código de prueba:

public class T { 

    public static void main(String[] args) { 

     int n = 100000000; 
     String s1 = new String(""); 
     String s2 = new String(""); 
     String s3 = new String(""); 
     String s4 = new String(""); 
     String s5 = new String(""); 

     long t = System.currentTimeMillis(); 
     for (int i = 0; i < n; i++) { 
      foo(); 
     } 
     System.err.println(System.currentTimeMillis() - t); 


     t = System.currentTimeMillis(); 
     for (int i = 0; i < n; i++) { 
      baz(s1, s2, s3, s4, s5); 
     } 
     System.err.println(System.currentTimeMillis() - t); 

     t = System.currentTimeMillis(); 
     for (int i = 0; i < n; i++) { 
      bar(s1, s2, s3, s4, s5); 
     } 
     System.err.println(System.currentTimeMillis() - t); 

    } 

    static void foo() { 
    } 

    static void bar(String a1, String a2, String a3, String a4, String a5) { 
    } 

    static void baz(String... a) { 
    } 
} 

En mi máquina la producción media es:

78 
4696 
78 

Parece que las variables de paso a métodos es sin costo?! Bueno !

¡Pero usar varags es 60 veces más lento! Por qué ?

Una explicación podría ser que el programa debe crear la matriz en el montón y el tiempo es gastado por GC. Pero por menos bucles sigo teniendo como salida:

0 
62 
0 

Lo que está pasando este tiempo extra de todos modos y el compilador tiene toda la información para resolver este a una llamada variable de corrección ...

No es mi intención para optimizar para eso, pero he encontrado este curioso ...

actualización

he añadido una nueva prueba

t = System.currentTimeMillis(); 
for (int i = 0; i < n; i++) { 
    baz(s1); 
} 
System.err.println(System.currentTimeMillis() - t); 

Y esta versión de un argumento todavía es 30 veces más lenta. Tal vez hay una ArrayList.toArray() detrás de la escena?

Por lo tanto, tenga en cuenta los métodos de varags innecesarios en su código y refactor para fijar la longitud. Eso podría ser un impulso de rendimiento.

Respuesta

16

La lista estática de argumentos es bastante diferente de una matriz. Cuando los pasa de esa manera, el compilador reserva espacio para las referencias y las rellena cuando se llama al método.

Varargs es un equivalente de matriz. Para llamar a dicho método, es necesario crear y poblar la matriz en tiempo de ejecución. Es por eso que observas la diferencia.

String[] y String... son sinónimos. Si los comparaste, deberías ver un rendimiento idéntico.

+0

Sí, será lo mismo, ya que los varargs son azúcar sintáctico transformado en llamadas de matriz antes de la compilación efectiva. – Riduidel

+0

Esto es básicamente correcto, aunque creo que debe aclarar que la diferencia es que varargs requiere que la JVM asigne y complete una matriz. Ya sea en el montón o pila no es el problema (aunque sí, por supuesto, está en el montón). –

+0

@Sean Owen Gracias, actualizado. –

1

¡Problema interesante!

Esto es solo una suposición: detrás de escena, Var-args son solo arreglos. Crear esta matriz implícita y poblarla con los parámetros var-args puede llevar algo de tiempo; de ahí el golpe de rendimiento. Bueno, supongo.

0

Como se ha dicho, una matriz se mantiene cuando se utiliza var-args ...,

que también debe tratar de ver la influencia de la adición de "final" a los parámetros de cada métodos

i personalmente tengo una mejora de 2250 -> 2234 ms para la matriz.

+0

Los parámetros en Java realmente no se pueden finalizar, aún se pueden cambiar, por lo que esto no debería influir en nada. – helpermethod

+0

¿Cómo se puede cambiar un parámetro final? – Hardcoded

+0

final argumentos y variables no se pueden cambiar. Creo que el punto está mejor expresado así: hacer una * referencia de objeto * final significa que no puede cambiar la referencia, pero no significa que el objeto al que se refiere no puede cambiar de estado. –

7

Utilizando tanto la última jre6 y JRE7 consigo resultados diferentes a la suya e indican que varargs son 5 veces más rápido:

69 
69 
311 

Sin embargo, yo no saltar a conclusiones ya que esta referencia tiene varios defectos: la los parámetros no se usan en la función; la función no hace nada; los argumentos tienen el mismo valor JIT puede optimizar fácilmente este código y llamadas de función en línea. He modificado su ejemplo para hacer frente a los problemas obvios antes mencionados y obtuvo los siguientes resultados:

627 
7470 
7844 

La conclusión es: no dudan en utilizar varargs. Si su función es trivial, su llamada debe estar escrita por el JIT, y si no es así, la sobrecarga de los varargs probablemente será insignificante.