Question

Quelle est la différence entre le compilateur JIT et le CLR? Si vous compilez votre code pour il et que CLR l'exécute, que fait JIT? Comment la compilation de JIT at-elle changé avec l’ajout de génériques au CLR?

Était-ce utile?

La solution

Le JIT est un aspect du CLR.

Plus précisément, il s’agit de la partie responsable de la modification de CIL / MSIL (ci-après appelée IL) produite par le compilateur du langage d’origine (csc.exe pour Microsoft c # par exemple) en code machine natif du processeur actuel (et de l’architecture exposée) processus en cours, par exemple 32/64 bits). Si l’assemblage en question a été créé, le processus JIT n’est absolument pas nécessaire et le CLR exécutera ce code sans lui.

Avant d'utiliser une méthode qui n'a pas encore été convertie à partir de la représentation intermédiaire, il incombe à l'EJI de la convertir.
Exactement quand le JIT entrera en action est spécifique à la mise en œuvre et peut être modifié. Toutefois, la conception du CLR impose que le JIT se produise avant avant que le code correspondant ne soit exécuté, les machines virtuelles Java seraient en revanche libres d'interpréter le code pendant un certain temps, tandis qu'un thread distinct créait une représentation du code machine.
Le CLR "normal" utilise une l’approche par stub pré-JIT où les méthodes ne sont compilées que si elles sont utilisées. Cela implique que le stub de méthode natif initial soit un indirection permettant au JIT de compiler la méthode, puis de modifier l'appel d'origine pour ignorer le stub initial. L’édition compacte actuelle compile à la place toutes les méthodes sur un type lorsqu’il est chargé.

Pour répondre à l'ajout de génériques.

Il s’agit du dernier changement majeur apporté à la spécification IL et à JIT en termes de sémantique, par opposition aux détails d’implémentation internes.

Plusieurs nouvelles instructions IL ont été ajoutées et davantage d'options de métadonnées ont été fournies pour les types d'instrument et les membres. Des contraintes ont également été ajoutées au niveau IL.

Lorsque le JIT compile une méthode comportant des arguments génériques (explicitement ou implicitement via la classe qui le contient), il peut définir différents chemins de code (instructions de code machine) pour chaque type utilisé. En pratique, le JIT utilise une implémentation partagée pour tous les types de référence car les variables associées présenteront la même sémantique et occuperont le même espace (IntPtr.Size).

Chaque type de valeur recevra un code spécifique, ce qui explique en grande partie la taille réduite / accrue des variables de la pile / du tas. De même, en émettant l'opcode contraint avant les appels de méthode, de nombreux appels sur des types non référencés n'ont pas besoin de cocher la valeur pour appeler la méthode (cette optimisation est également utilisée dans les cas non génériques). Cela permet également de gérer correctement le comportement <T> par défaut et d'éliminer les comparaisons avec null (sans opération) (toujours faux) lorsqu'un type de valeur non Nullable est utilisé.

Si une tentative est faite au moment de l'exécution pour créer une instance d'un type générique via une réflexion, les paramètres de type seront validés par le temps d'exécution afin de garantir le respect des contraintes. Cela n'affecte pas directement le JIT sauf s'il est utilisé dans le système de types (peu probable si possible).

Autres conseils

Vous compilez votre code en IL qui est exécuté et compilé en code machine lors de l'exécution, c'est ce que l'on appelle JIT.

Modifier , pour préciser davantage la réponse (encore trop simplifiée):

Lorsque vous compilez votre code C # dans visual studio, il est transformé en IL que le CLR comprend, l’IL est le même pour toutes les langues qui s’exécutent sur le CLR (c’est ce qui permet au runtime .NET d’utiliser plusieurs langages et inter-op entre eux facilement).

Pendant l'exécution, l'IL est interprété en code machine (spécifique à l'architecture sur laquelle vous êtes), puis exécuté. Ce processus est appelé compilation Just In Time ou JIT en abrégé. Seul l'IL nécessaire est transformé en code machine (et une seule fois, & "Mis en cache & Une fois compilé en code machinec), juste à temps avant d'être exécuté, le nom JIT.

Voici à quoi cela ressemblerait pour C #

  

Code C # > Compilateur C # <=> IL <=> Runtime .NET <=> Compilateur JIT <=> Machinecode <=> Exécution

Et voici à quoi cela ressemblerait pour VB

  

Code VB <=> Compilateur VB <=> IL <=> Runtime .NET <=> Compilateur JIT <=> Machinecode <=> Exécution

Et comme vous pouvez le constater, les deux premières étapes sont uniques à chaque langue et, une fois qu’elles ont été transformées en IL, elles sont identiques. C’est la raison pour laquelle, comme je l’ai déjà dit, vous pouvez utiliser plusieurs langues différentes par-dessus. NET

Comme le dit Jon Skeet, JIT fait partie du CLR. En gros, voici ce qui se passe sous le capot:

  1. Votre code source est compilé en un code d'octet appelé langage intermédiaire commun (CIL).
  2. Les métadonnées de chaque classe et de chaque méthode (et de toute autre chose: O) sont incluses dans l'en-tête PE de l'exécutable résultant (que ce soit une dll ou un exe).
  3. Si vous produisez un fichier exécutable, l'en-tête PE comprend également un programme d'amorçage classique chargé de charger le CLR (Common Language Runtime) lors de l'exécution de votre fichier exécutable.

Maintenant, quand vous exécutez:

  1. Le programme d'amorçage initialise le CLR (principalement en chargeant l'assembly mscorlib) et lui demande d'exécuter votre assembly.
  2. Le CLR exécute votre entrée principale.
  3. À présent, les classes ont une table de vecteurs contenant les adresses des fonctions de méthode. Ainsi, lorsque vous appelez MyMethod, cette table est recherchée, puis un appel correspondant à l'adresse est effectué. Au démarrage, TOUTES les entrées de toutes les tables ont l’adresse du compilateur JIT.
  4. Lorsqu'un appel à l'une de ces méthodes est effectué, le JIT est appelé à la place de la méthode réelle et prend le contrôle. Le JIT compile ensuite le code CIL en un code d'assemblage réel pour l'architecture appropriée.
  5. Une fois le code compilé, le JIT entre dans la table des vecteurs de méthode et remplace l'adresse par celui du code compilé, de sorte que chaque appel ultérieur n'appelle plus le JIT.
  6. Enfin, le JIT gère l’exécution du code compilé.
  7. Si vous appelez une autre méthode qui n'a pas encore été compilée, revenez à 4 ... et ainsi de suite ...

Le JIT est fondamentalement une partie du CLR. Le ramasse-miettes en est un autre. C’est un autre problème, et je suis extrêmement sous-qualifié pour commenter:)

Je sais que le fil est assez vieux, mais j'ai pensé que je pourrais mettre dans l'image qui m'a fait comprendre JIT. Il est tiré de l'excellent livre CLR via C # de Jeffrey Ritcher . Dans l'image, les métadonnées dont il parle sont les métadonnées émises dans l'en-tête de l'assembly où sont stockées toutes les informations sur les types de l'assembly:

Image JIT du CLR via C #

1) lors de la compilation du programme .net, le code du programme .net est converti en code de langage intermédiaire (IL)

2) lors de l'exécution du programme, le code de langue intermédiaire est converti en code natif du système d'exploitation au fur et à mesure de l'appel d'une méthode; c'est ce qu'on appelle la compilation JIT (Just in Time).

  1. Le langage CLR (Common Language Runtime) est un interpréteur, tandis que le compilateur Just In Time (JIT) est un compilateur dans .Net Framework.

2.JIT est le compilateur interne de .NET qui extrait le code MSICL (MicroSoft Intermediate Code Language) de CLR et l’exécute en instructions spécifiques à une machine, tandis que le CLR fonctionne comme un moteur. Sa tâche principale est de fournir du code MSICL à JIT pour assurer ce code est entièrement compilé selon les spécifications de la machine.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top