2009-08-10 15 views

Respuesta

42

Nota: esta respuesta se encuentra en un contexto "por ejecución".El código normalmente está JITted cada vez que ejecuta el programa. Usando ngen o .NET Native cambios que historia, también ...

A diferencia de HotSpot, el CLR JIT compila siempre exactamente una vez por ciclo. Nunca lo interpreta, y nunca vuelve a compilarse con una optimización más exhaustiva que antes en función del uso real.

Esto puede cambiar, por supuesto, pero ha sido así desde la v1 y no espero que cambie pronto.

La ventaja es que hace que el JIT mucho más simple - no hay necesidad de considerar "viejo" código que ya se está ejecutando, deshacer optimizaciones basado en premisas que ya no son válidas, etc.

Un punto a. El favor de NET es que la mayoría de los lenguajes de CLR hacen que los métodos no sean virtuales por defecto, lo que significa que se puede hacer mucho más inline. HotSpot puede alinear un método hasta que se anula por primera vez en qué punto deshace la optimización (o hace algunas cosas inteligentes en algunos casos para seguir usando el código en línea de manera condicional, según el tipo real). Con menos métodos virtuales de los que preocuparse, .NET puede ignorar en gran medida el dolor de no poder hacer nada virtual.

EDITAR: Lo anterior describe el marco de escritorio. Compact Framework arroja código nativo cuando lo desea, JITting nuevamente según sea necesario. Sin embargo, esto todavía no es como la optimización adaptativa HotSpots.

El micro framework no parece JIT para nada, interpretando el código en su lugar. Esto tiene sentido para dispositivos muy restringidos. (No puedo decir que sé mucho sobre el micro framework.)

+0

Veo ... así que la única vez que el CLR .Net se ejecuta en modo interpretado es si el JIT está apagado por completo (para la depuración). – jsight

+3

No creo que realmente interprete el código incluso entonces: el depurador puede pasar por el código compilado de manera adecuada, eso es todo. Mono * does * tiene un intérprete sin embargo. –

+1

Curiosamente, .net MF (MicroFramework para dispositivos integrados) interpreta IL en lugar de compilarlo. –

14

El .NET runtime siempre compila el código JIT antes de la ejecución. Por lo tanto, nunca se interpreta.

Puede encontrar algunas lecturas más interesantes en CLR Design Choices con Anders Hejlsberg. Especialmente la parte:

He leído que Microsoft decidió que IL siempre se compilará, nunca se interpretará. ¿De qué manera la información del tipo de codificación en las instrucciones ayuda a los intérpretes a ejecutar de manera más eficiente?

Anders Hejlsberg: Si un intérprete puede simplemente hacer a ciegas lo que dicen las instrucciones sin necesidad de rastrear lo que está en la parte superior de la pila, puede ir más rápido. Cuando ve un iadd, por ejemplo, el intérprete no tiene que averiguar primero qué tipo de agregar es, sabe que es un entero. Suponiendo que alguien ya haya verificado que la pila parece correcta, es seguro reducir algo de tiempo allí, y eso le preocupa a un intérprete. En nuestro caso, sin embargo, nunca tuvimos la intención de apuntar a un escenario interpretado con el CLR. Intentamos siempre JIT [compilación justo a tiempo], y para los fines del JIT, necesitábamos rastrear la información del tipo de todos modos. Como ya tenemos la información del tipo, en realidad no nos compra nada para ponerlo en las instrucciones.

Bill Venners: Muchas JVM modernas [máquinas virtuales Java] hacen optimización adaptativa, donde comienzan interpretando bytecodes. Ellos perfilan la aplicación mientras se ejecuta para encontrar el 10% a 20% del código que se ejecuta del 80% al 90% del tiempo, luego lo compilan en nativo. Sin embargo, no necesariamente compilan esos códigos de byte justo a tiempo. Los códigos de bytes de un método aún pueden ser ejecutados por el intérprete, ya que se compilan en origen y se optimizan en segundo plano. Cuando el código nativo está listo, puede reemplazar los bytecodes. Al no enfocarse en un escenario interpretado, ¿ha descartado por completo ese enfoque de ejecución en un CLR?

Anders Hejlsberg: No, no hemos descartado por completo. Aún podemos interpretar. Simplemente no estamos optimizados para la interpretación. No estamos optimizados para escribir el intérprete de mayor rendimiento que solo interpretará. No creo que nadie haga eso más. Para un decodificador hace 10 años, eso podría haber sido interesante. Pero ya no es interesante. Las tecnologías JIT han llegado al punto en el que puede tener múltiples estrategias JIT posibles. Incluso puede imaginar el uso de un JIT rápido que simplemente se rompe rápidamente, y luego, cuando descubrimos que estamos ejecutando un método en particular todo el tiempo, utilizando otro JIT que dedica un poco más de tiempo y hace un mejor trabajo de optimización. Hay mucho más que puedes hacer JIT-wise.

0

No lo creo, y no creo que deba hacerlo nunca.

¿Cómo podría el JIT saber cuántas veces se llamaría un método en particular? ¿No influiría la frecuencia de la interpretación en la decisión?

También me pregunto qué tan bien un compilador JIT sería capaz de analizar una función para determinar si la interpretación sería mejor sin interpretar la función en sí misma. Y teniendo en cuenta ese hecho (que se ha llevado a cabo al menos una pasada del método), ¿no sería mejor simplemente compilar cada método para reducir la sobrecarga de tratar de determinar qué métodos se compilan en primer lugar?

+0

@Andrew: las métricas de rendimiento en tiempo de ejecución pueden indicarle si se debe jodir algo, así como la agresividad con que se debe realizar (por ejemplo, algunas optimizaciones de JIT consumen más tiempo que otras). – jsight

+0

Solo una idea (dudo que HotSpot funcione así) - podrías analizar algunas cosas (como la longitud del método) estáticamente (mientras generas bytecode) y tomar una decisión que, y luego, simplemente marcar este método con el bit "no compilar" , por lo que JIT sabría que no debería compilarlo, cuando sea necesario, en su lugar, recurra al intérprete. –

+3

http://java.sun.com/products/hotspot/whitepaper.html - HotSpot puede reemplazar el código en su lugar, incluso mientras ese código se está ejecutando en la pila. Por lo tanto, un ciclo puede comenzar en modo interpretado, pero completar en modo compilado JIT una vez que se complete la recompilación. – jsight

3

Sería bueno ver algunos JIT basados ​​en trazas en el futuro para dispositivos con poca memoria. Principalmente interpretaría, encontraría puntos calientes y los convertiría en ensambladores y almacenarlos en caché. Creo que esto es lo que Google hace con su JIT de Android y Microsoft Research tiene un proyecto de investigación en curso para JIT basado en trazas.

he encontrado un artículo, SPUR: A Trace-Based JIT Compiler for CIL .. Tal vez algo de esto hará que sea en el día CLR uno?

Cuestiones relacionadas