2011-09-01 16 views
6

Estoy tratando de probar la velocidad de autoboxing y unboxing en Java, pero cuando trato de compararlo con un loop vacío en un primitivo, noté una cosa curiosa. Este fragmento:Java: ¿cuánto tiempo usa un ciclo vacío?

for (int j = 0; j < 10; j++) { 
    long t = System.currentTimeMillis(); 
    for (int i = 0; i < 10000000; i++) 
     ; 
    t = System.currentTimeMillis() - t; 
    System.out.print(t + " "); 
} 

Cada vez que funciono esto, se devuelve el mismo resultado:

6 7 0 0 0 0 0 0 0 0

¿Por qué los dos primeros bucles siempre llevar algún tiempo, a continuación, el resto sólo parecen ser omitidos por el sistema?

In this answer to this post, se dice que la compilación Just-In-Time será capaz de optimizar esto. Pero si es así, ¿por qué los dos primeros bucles aún tardaron un tiempo?

+3

Creo que 'System.nanoTime()' está más indicado para estas pruebas (la máquina virtual cliente/servidor también debería marcar la diferencia) –

+0

Sí, claro, milisegundos a menudo son demasiado gruesos. –

Respuesta

20

Desencadenantes JIT DESPUÉS de que se haya ejecutado varias veces un código determinado.

El HotSpot JVM intentará identificar los "puntos calientes" en su código. Los puntos conflictivos son partes de su código que se ejecutan muchas veces. Para hacer esto, la JVM "contará" las ejecuciones de varias instrucciones, y cuando determine que una determinada pieza se ejecuta con frecuencia, activará el JIT. (Esta es una aproximación, pero es fácil de entender explicada de esta manera).

El JIT (Just-In-Time) toma ese trozo de código e intenta hacerlo más rápido.

Las técnicas utilizadas por el JIT para hacer que su código se ejecute más rápido son mucho, pero el que más comúnmente crea confusión son:

  1. Se tratará de determinar si ese pedazo de código utiliza variables que son no se usa en ningún otro lado (variables inútiles), y eliminarlos.
  2. Si adquiere y libera el mismo bloqueo varias veces (como llamar a métodos sincronizados del mismo objeto), puede adquirir el bloqueo una vez y hacer todas las llamadas en un único bloque sincronizado
  3. Si accede a miembros de un objeto que no se declaran volátiles, puede decidir optimizarlo (colocando valores en registros y similares), creando resultados extraños en código multihilo.
  4. Aplicará métodos en línea, para evitar el costo de la llamada.
  5. Transformará bytecode en código de máquina.
  6. Si el ciclo es completamente inútil, podría eliminarse por completo.

Por lo tanto, la respuesta correcta a su pregunta es que un bucle vacío, después de JITed, no tarda en ejecutarse ... lo más probable es que ya no exista.

Una vez más, hay muchas otras optimizaciones, pero en mi experiencia, estas son algunas de las que han creado más dolores de cabeza.

Además, JIT se está mejorando en cualquier versión nueva de Java, y algunas veces es incluso un poco diferente según la plataforma (ya que, en cierta medida, es específica de la plataforma). Las optimizaciones hechas por el JIT son difíciles de entender, porque generalmente no se pueden encontrar usando javap e inspeccionando bytecode, incluso si en versiones recientes de Java algunas de estas optimizaciones se han movido al compilador directamente (por ejemplo, desde Java 6 el compilador es capaz de detectar y advertir sobre variables locales no utilizadas y métodos privados).

Si está escribiendo algunos bucles para probar algo, generalmente es una buena práctica tener el bucle dentro de un método, llamar al método unas veces ANTES de sincronizarlo, darle una ronda de "aceleración" y luego realizar el ciclo cronometrado

Esto generalmente desencadena el JIT en un programa simple como el suyo, incluso si no hay garantía de que realmente se active (o que incluso exista en una plataforma determinada).

Si quiere volverse paranoico con el tiempo JIT o no JIT (lo hice): realice una primera ronda, cronometrando cada ejecución del ciclo, y espere hasta que el tiempo se estabilice (por ejemplo, diferencia del promedio inferior a 10 %), luego comienza con tu tiempo "real".

7

El JIT no entra en juego en un trozo de código hasta que determina que hay algún beneficio al hacerlo. Eso significa que los primeros pasos a través de algún código no serán JIT.

+0

Gracias! Ya veo, pero ¿qué puede hacer el bucle vacío? O como dijo @Simone Gianni, JIT (se garantiza que) no se activará a menos que el ciclo se haya ejecutado durante algún tiempo. EDIT: ¡Gracias de nuevo! Recibí la respuesta de la respuesta de Simone :) –

Cuestiones relacionadas