¿Por qué la JVM no almacena en caché el código compilado JIT?

107

La implementación canónica de JVM de Sun aplica una optimización bastante sofisticada al código de bytes para obtener velocidades de ejecución casi nativas después de que el código se haya ejecutado varias veces.

La pregunta es, ¿por qué este código compilado no se almacena en caché en el disco para su uso durante los usos posteriores de la misma función / clase?

Tal como está, cada vez que se ejecuta un programa, el compilador JIT se activa de nuevo, en lugar de utilizar una versión precompilada del código. ¿No agregaría esta característica un impulso significativo al tiempo de ejecución inicial del programa, cuando el código de bytes se está interpretando esencialmente?

Chinmay Kanchi
fuente
4
Un hilo que discute este problema: javalobby.org/forums/thread.jspa?threadID=15812
miku
2
Pero una pregunta poco probable que atraiga una respuesta definitiva.
bmargulies
1
No estoy seguro de un aumento "significativo", porque entonces tendrías que cargar material JITted desde el disco en lugar de JITing en la memoria. Podría acelerar las cosas, pero caso por caso.
R. Martinho Fernandes
1
¡Gracias a todos por las excelentes respuestas! Todas las respuestas fueron igualmente válidas, así que fui con la comunidad en esta ...
Chinmay Kanchi
Esta es una buena pregunta si me preguntas :)
Alfred

Respuestas:

25

Sin recurrir a cortar y pegar el enlace que publicó @MYYN, sospecho que esto se debe a que las optimizaciones que realiza la JVM no son estáticas, sino dinámicas, basadas en los patrones de datos y en los patrones de código. Es probable que estos patrones de datos cambien durante la vida útil de la aplicación, lo que hace que las optimizaciones en caché sean menos que óptimas.

Por lo tanto, necesitaría un mecanismo para establecer si las optimizaciones guardadas siguen siendo óptimas, momento en el que también podría volver a optimizar sobre la marcha.

skaffman
fuente
6
... o simplemente podría ofrecer la persistencia como una opción , como lo hace la JVM de Oracle: capacite a los programadores avanzados para optimizar el rendimiento de sus aplicaciones cuando y donde simplemente sepan que los patrones no están cambiando, bajo su responsabilidad. ¡¿Por qué no?!
Alex Martelli
2
Porque probablemente no valga la pena. Si ni SUN, IBM ni BEA consideraron que valía la pena por sus JVM de rendimiento, habrá una buena razón para ello. Quizás su optimización de RT sea más rápida que la de Oracle, razón por la cual Oracle la almacena en caché.
skaffman
9
¿Por qué no tomar las optimizaciones almacenadas como punto de partida, para utilizar lo aprendido en ejecuciones anteriores? A partir de ahí, JIT podría funcionar como de costumbre y volver a optimizar cosas. Al apagar, ese código podría persistir nuevamente y usarse en la siguiente ejecución como un nuevo punto de partida.
Puce
1
@Puce La única razón en la que puedo pensar es que AFAIK, no obtienes estadísticas de perfiles al ejecutar código optimizado. Entonces no tendrías forma de mejorar ...
maaartinus
1
Personalmente, estaría bien con una opción de "persistir la información de perfil JIT entre ejecuciones" con todas las advertencias de que "esto solo será válido con exactamente la misma JVM, los mismos datos, etc. y de lo contrario se ignorará". Con respecto a por qué esto no se ha implementado, esperaría que la complejidad adicional de persistir y validar los datos semilla JIT fuera demasiado para tomar recursos de otros proyectos. Dada la posibilidad de elegir entre este y los flujos lambda + de Java 8, preferiría el último.
Thorbjørn Ravn Andersen
25

De hecho, la JVM de Oracle está documentada para hacerlo, citando a Oracle,

el compilador puede aprovechar el modelo de resolución de clases de Oracle JVM para, opcionalmente, conservar los métodos compilados de Java en las llamadas, sesiones o instancias de bases de datos. Tal persistencia evita la sobrecarga de recompilaciones innecesarias entre sesiones o instancias, cuando se sabe que semánticamente el código Java no ha cambiado.

No sé por qué todas las implementaciones sofisticadas de VM no ofrecen opciones similares.

Alex Martelli
fuente
8
Porque otras JVM sofisticadas no tienen un RDBMS empresarial excelente para almacenar cosas :)
skaffman
¡Guauu! eso significa que las compilaciones se almacenan en caché a veces. ¡Estas son buenas noticias!
Sandeep Jindal
El J9 de IBM también está documentado para hacerlo.
user314104
9
Tenga en cuenta que esta JVM de Oracle es la que se encuentra dentro de la base de datos de Oracle, no la descarga que Oracle obtuvo al comprar Sun.
Thorbjørn Ravn Andersen
14

Una actualización de las respuestas existentes: Java 8 tiene un JEP dedicado a resolver esto:

=> JEP 145: Código compilado en caché . Enlace nuevo .

A un nivel muy alto, su objetivo declarado es :

Guarde y reutilice el código nativo compilado de ejecuciones anteriores para mejorar el tiempo de inicio de grandes aplicaciones Java.

Espero que esto ayude.

Eugen
fuente
3
La función no ha llegado a la versión final .
Assylias
5

Excelsior JET tiene un compilador JIT de almacenamiento en caché desde la versión 2.0, lanzado en 2001. Además, su compilador AOT puede volver a compilar el caché en un solo objeto DLL / compartido utilizando todas las optimizaciones.

Dmitry Leskov
fuente
3
Sí, pero la pregunta era sobre la JVM canónica, es decir, la JVM de Sun. Soy muy consciente de que hay varios compiladores AOT para Java, así como otras JVM de almacenamiento en caché.
Chinmay Kanchi
0

No conozco las razones reales, no estoy involucrado de ninguna manera en la implementación de JVM, pero puedo pensar en algunas plausibles:

  • La idea de Java es ser un lenguaje que se puede escribir una vez y ejecutar en cualquier lugar, y poner cosas precompiladas en el archivo de clase es una violación de eso (solo "un poco" porque, por supuesto, el código de bytes real todavía estaría allí)
  • Aumentaría el tamaño de los archivos de clase porque tendría el mismo código allí varias veces, especialmente si ejecuta el mismo programa en varias JVM diferentes (lo cual no es realmente infrecuente, cuando considera que las diferentes versiones son diferentes JVM, lo que realmente tengo que hacer)
  • Es posible que los archivos de clase en sí mismos no se puedan escribir (aunque sería bastante fácil verificarlo)
  • Las optimizaciones de JVM se basan parcialmente en información en tiempo de ejecución y en otras ejecuciones pueden no ser tan aplicables (aunque aún deberían proporcionar algún beneficio)

Pero realmente estoy adivinando, y como puede ver, realmente no creo que ninguna de mis razones sea un obstáculo real. Supongo que Sun simplemente no considera este soporte como una prioridad, y tal vez mi primera razón sea cercana a la verdad, ya que hacer esto habitualmente también podría llevar a la gente a pensar que los archivos de clases de Java realmente necesitan una versión separada para cada VM en lugar de ser multiplataforma.

Mi forma preferida sería tener un traductor de código de bytes a nativo separado que podría usar para hacer algo como esto explícitamente de antemano, creando archivos de clase que se compilan explícitamente para una máquina virtual específica, con posiblemente el código de bytes original en ellos para que también se puede ejecutar con diferentes VM. Pero eso probablemente proviene de mi experiencia: he estado haciendo principalmente Java ME, donde realmente duele que el compilador de Java no sea más inteligente en la compilación.

JaakkoK
fuente
1
hay un lugar en el archivo de clases para tales cosas, de hecho, esa era la intención original (almacenar el código JIT como un atributo en el archivo de clases).
TofuBeer
@TofuBeer: Gracias por la confirmación. Sospeché que ese podría ser el caso (eso es lo que habría hecho), pero no estaba seguro. Editado para eliminar eso como una posible razón.
JaakkoK
Creo que dio en el clavo con su última viñeta. Los demás podrían solucionarse, pero creo que esa última parte es la razón principal por la que no se conserva el código JIT.
Sasha Chedygov
1
El último párrafo sobre el compilador explícito de código de bytes a nativo es lo que tiene actualmente en .NET con NGEN ( msdn.microsoft.com/en-us/library/6t9t5wcf(VS.71).aspx ).
R. Martinho Fernandes