2009-03-02 17 views
36

¿Cuál es la diferencia entre el compilador JIT y CLR? Si compila su código para il y CLR ejecuta ese código, ¿qué está haciendo el JIT? ¿Cómo ha cambiado la compilación de JIT con la adición de genéricos al CLR?CLR contra JIT

+0

Formulé mi respuesta desde que la aceptó. Si esto hace que sea demasiado detallado y ya no sea lo que consideraría una respuesta aceptable, agregue un comentario para decirlo y lo reduciré/revertiré. Me pareció una pena perder la información de las otras respuestas – ShuggyCoUk

Respuesta

42

El JIT es un aspecto de la CLR.

Específicamente es la parte responsable de cambiar CIL/MSIL (en lo sucesivo denominado IL) producido por el compilador del lenguaje original (csc.exe para Microsoft C# por ejemplo) en código de máquina nativo del procesador actual (y la arquitectura que expone en el proceso actual, por ejemplo 32/64bit). Si el conjunto en cuestión fue ngen'd entonces el proceso JIT es completamente innecesario y el CLR ejecutará este código sin problemas.

Antes de que se utilice un método que aún no se haya convertido a partir de la representación intermedia, es responsabilidad del JIT convertirlo.
Exactamente cuando el JIT se activará es específico de la implementación, y está sujeto a cambios. Sin embargo, el diseño de CLR exige que el JIT pase antes de que se ejecute el código correspondiente, en cambio las JVM tendrían la libertad de interpretar el código durante un tiempo, mientras que un hilo separado crea una representación de código de máquina.
El CLR 'normal' usa un pre-JIT stub approach donde los métodos se compilan solo cuando se usan. Esto implica que el trozo de método nativo inicial sea un indirecto para indicar al JIT que compile el método y luego modifique la llamada original para omitir el trozo inicial. La edición compacta actual en su lugar compila todos los métodos en un tipo cuando se carga.

Para abordar la adición de genéricos.

Este fue el último cambio importante en la especificación IL y JIT en términos de su semántica en comparación con sus detalles de implementación interna.

Se agregaron varias nuevas instrucciones de IL y se proporcionaron más opciones de metadatos para los tipos y miembros de instrumentos. También se agregaron restricciones en el nivel IL.

Cuando el JIT compila un método que tiene argumentos genéricos (explícita o implícitamente a través de la clase contenedora) puede configurar diferentes rutas de código (instrucciones de código de máquina) para cada tipo utilizado.En la práctica, el JIT utiliza una implementación compartida para todos los tipos de referencia, ya que las variables para estos exhibirán la misma semántica y ocuparán el mismo espacio (IntPtr.Size).

Cada tipo de valor obtendrá un código específico generado para él, tratar con el tamaño reducido/aumentado de las variables en la pila/montón es una razón importante para esto. Además, al emitir el código de operación restringido antes de las llamadas al método, muchas invocaciones en tipos no de referencia no necesitan incluir el valor para llamar al método (esta optimización también se usa en casos no genéricos). Esto también permite que el comportamiento predeterminado <T> se maneje correctamente y que las comparaciones con null se eliminen como no operaciones (siempre es falso) cuando se usa un tipo de valor que no admite valores NULL.

Si durante el tiempo de ejecución se intenta crear una instancia de un tipo genérico mediante reflexión, los parámetros de tipo serán validados por el tiempo de ejecución para garantizar que se superen las restricciones. Esto no afecta directamente al JIT a menos que se use dentro del sistema de tipo (aunque es poco probable).

64

Compila el código en IL que se ejecuta y compila en código de máquina durante el tiempo de ejecución, esto es lo que se llama JIT.

Editar, para dar cuerpo a la respuesta un poco más (todavía excesivamente simplificada):

Cuando se compila el código C# en Visual Studio que se convirtió en IL que el CLR entiende, la IL es el mismo para todos los idiomas que se ejecutan en la parte superior de CLR (que es lo que permite que el tiempo de ejecución de .NET use varios idiomas y entre ellos fácilmente).

Durante el tiempo de ejecución, el IL se interpreta en código máquina (que es específico de la arquitectura en la que se encuentra) y luego se ejecuta. Este proceso se llama compilación Just In Time o JIT para abreviar. Solo el IL que se necesita se transforma en código de máquina (y solo una vez, se "almacena en caché" una vez que se compila en código de máquina), justo a tiempo antes de que se ejecute, de ahí el nombre JIT.

Esto es lo que se vería como para C#

C# Código > compilador de C# > IL > .NET compilador de ejecución > JIT > Machinecode > Ejecución

Y esto es lo que se vería como para VB

Código VB > VB Compilador > IL > .NET Runtime > compilador JIT > Machinecode > Ejecución

Y como se puede ver solamente los dos primeros pasos son únicos para cada idioma, y ​​todo después de que ha sido convertida en IL es el mismo, que es, como dije antes, la razón por la que puede ejecutar varios idiomas diferentes además de .NET

+2

-1 para referirse a IL como bytecode, es una semántica de Java. IL (anteriormente MSIL) es el término correcto, no confundas los dos. Cambia eso y tienes mi voto. –

+0

@John Leidegren: Buen punto, lo cambió. – thr

+0

¿Es cierto que el JIT compila el código para código de máquina la primera vez que ejecuta el programa, y ​​después de eso se omite la compilación y se utiliza el código compilado? De ser así, podría valer la pena incorporar esto en su respuesta. –

23

El JIT es básicamente parte del CLR. El recolector de basura es otro. El lugar donde pones responsabilidades de interoperabilidad, etc. es otro asunto, y uno donde estoy muy poco calificado para comentar :)

+1

@Ted: ¿Era este el tipo de cosa que te interesaba? No ofrecí una explicación más detallada (como la de Fredrik) porque pensé que ya sabías la mayor parte de ese tipo de cosas y te interesaba la relación entre el CLR y el JIT. –

+0

No, nunca lo voté. Creo que todas las respuestas son realmente buenas. Creo que debería haber hecho la pregunta de otra manera. Estaba realmente interesado en la relación entre el CLR y el compilador JIT y cómo ha cambiado con la adición de genéricos. –

27

Como dice Jon Skeet, JIT es parte de la CLR. Básicamente esto es lo que está sucediendo bajo el capó:

  1. Su código fuente se compila en un código de bytes conocido como el lenguaje intermedio común (CIL).
  2. Los metadatos de todas las clases y todos los métodos (y todas las demás cosas: O) se incluyen en el encabezado PE del ejecutable resultante (ya sea un dll o un exe).
  3. Si está produciendo un ejecutable, el encabezado PE también incluye un bootstrapper convencional que se encarga de cargar el CLR (Common Language Runtime) cuando ejecuta el archivo ejecutable.

Ahora, cuando se ejecuta:

  1. El bootstraper inicializa el CLR (principalmente por la carga de la asamblea mscorlib) y le indica que debe ejecutar su montaje.
  2. El CLR ejecuta su entrada principal.
  3. Ahora, las clases tienen una tabla vectorial que contiene las direcciones de las funciones del método, de modo que cuando se llama a MyMethod, se busca en esta tabla y luego se realiza una llamada correspondiente a la dirección. Al inicio TODAS las entradas para todas las tablas tienen la dirección del compilador JIT.
  4. Cuando se realiza una llamada a uno de dichos métodos, se invoca el JIT en lugar del método real y toma el control. El JIT luego compila el código CIL en un código de ensamblaje real para la arquitectura apropiada.
  5. Una vez que se compila el código, el JIT entra en la tabla de vectores de métodos y reemplaza la dirección con la del código compilado, de modo que cada llamada subsiguiente ya no invoca el JIT.
  6. Finalmente, el JIT maneja la ejecución al código compilado.
  7. Si se llama a otro método que aún no han de ser compilado a continuación, volver a 4 ... y así sucesivamente ...
+1

¡Maldición! Deja de llamarlo bytecode, es IL, una representación de lenguaje intermedio. Como el tamaño de las instrucciones IL son palabras de 16 bits. –

+1

Me temo que estás peleando una batalla perdida en este caso John :) Creo que el "código intermedio" es un término general razonable en el que quieres incluir los de Java, 'net's, LLVM's etc. pero maldito si el bytecode no es rápido ... – ShuggyCoUk

+0

Si hablas bytecode, supongo que hablas de bytecode de Java. Si dice IL, supongo que está hablando de la plataforma .NET. Es tan simple como eso. Quiero mantener viva esa distinción. –

15

Sé que el hilo es bastante viejo, pero pensé que podría poner en la imagen que me hizo entender JIT. Es del excelente libro CLR via C# by Jeffrey Ritcher. En la imagen, los metadatos que está hablando son los metadatos emitida en la cabecera de montaje donde se almacena toda la información acerca de los tipos en la asamblea:

JIT image from CLR via C#

2

1) al compilar el programa .NET, el programa .NET el código se convierte en código de idioma intermedio (IL)

2) al ejecutar el programa, el código de idioma intermedio se convierte en código nativo del sistema operativo cuando se llama un método; esto se llama compilación JIT (Just in Time).

-2
  1. Common Language Runtime (CLR) es un intérprete mientras que Just In Time (JIT) es el compilador en .Net Framework.

2.JIT es el compilador interna de .NET que toma el código de Microsoft Intermedio de códigos de idiomas (MSICL) de CLR y lo ejecuta a instrucciones específicas de máquina, mientras que CLR funciona como motor de su tarea principal es proporcionar el código de MSICL JIT para garantizar que el código esté completamente compilado según las especificaciones de la máquina.

+0

Micro ** S ** oft? ¿Por qué? –