web-dev-qa-db-fra.com

CLR vs JIT

Quelle est la différence entre le compilateur JIT et CLR? Si vous compilez votre code à IL et CLR exécute ce code, quel est le JIT? Comment la compilation JIT a-t-elle changé avec l'ajout de génériques au CLR?

42
Ted Smith

Le JIT est un aspect du CLR.

Spécifiquement, c'est la partie responsable de la modification du CIL/MSIL (ci-après appelée IL) produite par le compilateur de langue d'origine (CSC.EXE pour Microsoft C # par exemple) dans le code de machine natif du processeur actuel (et l'architecture qu'il expose dans le processus en cours , par exemple 32/64 bits). Si l'assemblage en question était NGEN'D, le processus JIT est totalement inutile et le CLR fonctionnera bien ce code sans elle.

Avant qu'une méthode n'est utilisée qui n'a pas encore été convertie de la représentation intermédiaire, il est la responsabilité du JIT de le convertir.
[.____] exactement Quand Le JIT sera lancé dans la mise en œuvre spécifique et sujette au changement. Cependant, la conception CLR charge que le JIT arrive avant ​​Le code pertinent exécute, JVM est en contraste, serait libre d'interpréter le code pendant un moment, tandis qu'un thread distinct crée une représentation de code de machine.
Le CLR "normal" utilise un approche de talon avant JIT Où par des méthodes ne sont compilées que comme elles sont utilisées. Cela implique que la méthode initiale de la méthode natif soit une indirection pour indiquer à la JIT de compiler la méthode puis modifier l'appel d'origine pour passer au-delà du talon initial. L'édition compacte actuelle compile plutôt toutes les méthodes d'un type lorsqu'elle est chargée.

Pour adresser l'ajout de génériques.

C'était le dernier changement majeur de l'IL Spécification et du JIT en termes de sémantique par opposition à ses détails de mise en œuvre internes.

Plusieurs nouvelles instructions de IL ont été ajoutées et plus d'options de méta-de-données ont été fournies pour instrumenter les types et les membres. Des contraintes ont également été ajoutées au niveau de l'IL.

Lorsque le JIT compile une méthode qui a des arguments génériques (explicitement ou implicitement via la classe contenant), il peut configurer différents chemins de code (instructions de code de 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 de ceux-ci présenteront la même sémantique et occuperont le même espace (IntPTR.SIZE).

Chaque type de valeur obtiendra un code spécifique généré pour celui-ci, traitant de la taille réduite/accrue des variables sur la pile/le tas la constitue une raison majeure de cela. Également en émettant l'opcode contraint avant les appels de méthode, de nombreuses invocations sur les types de non-référence n'ont pas besoin de casser la valeur pour appeler la méthode (cette optimisation est également utilisée dans des cas non génériques). Cela permet également au comportement par défaut <T> D'être correctement traité et des comparaisons à NULL pour être supprimées, car aucun ops (toujours faux) lorsqu'un type de valeur non nullable est utilisé.

Si une tentative est faite au moment de la création d'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 pour vous assurer qu'ils transmettent toutes les contraintes. Cela n'affecte pas directement le JIT, sauf si cela est utilisé dans le système de type (peu probable que possible).

47
ShuggyCoUk

Vous compilez votre code à IL qui est exécuté et compilé au code de la machine pendant l'exécution, c'est ce qu'on appelle JIT.

éditer, pour éliminer la réponse un peu plus (encore trop simplifié):

Lorsque vous compilez votre code C # dans Visual Studio, il est transformé en IL que le CLR comprend, l'IL est la même pour toutes les langues fonctionnant sur le CLR (ce qui permet au-dessus du temps d'exécution .NET d'utiliser plusieurs langues et inter-op entre eux facilement).

Pendant l'exécution, l'IL est interprété dans le code de la machine (spécifique à l'architecture que vous allez), puis il est exécuté. Ce processus est appelé juste dans la compilation de temps ou JIT pour le court. Seul l'IL nécessaire est transformé en code de machine (et une seule fois une fois, il est "mis en cache" une fois qu'il est compilé dans Machinecode), juste à temps Avant sa exécution, d'où le nom JIT.

C'est ce dont on ressemblerait pour C #

C # code > C # compilateur > Il > .Net runtime > JIT compiler > Exécution >

Et c'est ce que cela ressemblerait à VB

Code VB > VB compiler > Il > .Net runtime > JIT compiler > Machinecode > Exécution

Et comme vous pouvez le constater que seules les deux premières étapes sont uniques à chaque langue, et tout après avoir été transformé en IL est la même qui est la même qui est, comme je l'ai déjà dit, la raison pour laquelle vous pouvez exécuter plusieurs langues différentes sur .net.

73
thr

Comme le dit Jon Skeet, Jit fait partie du CLR. Fondamentalement, c'est ce qui se passe sous le capot:

  1. Votre code source est compilé dans un code octet connu comme langue intermédiaire commune (CIL).
  2. Les métadonnées de chaque classe et toutes les méthodes (et toutes les autres choses: 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 exécutable, l'en-tête PE comprend également une botte conventionnelle chargée de charger le CLR (runn-runtime de langue courante) lorsque vous vous exécutez exécutable.

Maintenant, lorsque vous exécutez:

  1. Le bootstraper initialise le CLR (principalement en chargement de l'ensemble MSCORLIB) et l'indique à exécuter votre montage.
  2. Le CLR exécute votre entrée principale.
  3. Maintenant, les classes ont une table de vecteur qui détiennent les adresses des fonctions de méthode, de sorte que lorsque vous appelez MyMethod, ce tableau est recherché, puis un appel correspondant à l'adresse est effectué. Lors du 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 invoqué au lieu de la méthode réelle et prend le contrôle. Le JIT compile ensuite le code CIL dans le code de montage réel pour l'architecture appropriée.
  5. Une fois que le code est compilé, le JIT passe dans la table de vecteur de méthode et remplace l'adresse avec l'un des codes compilés, de sorte que chaque appel ultérieur n'appelle plus le JIT.
  6. Enfin, le JIT gère l'exécution au code compilé.
  7. Si vous appelez une autre méthode qui n'a pas encore été compilée, revenez à 4 ... et ainsi de suite ...
29
Jorge Córdoba

Le JIT est fondamentalement partie du CLR. Le collecteur des ordures est un autre. Là où vous mettez des responsabilités interopérables, etc. est une autre affaire et l'une où je suis extrêmement sousquée de commenter :)

26
Jon Skeet

Je sais que le fil est assez vieux, mais je pensais que je pourrais mettre dans la photo qui m'a fait comprendre Jit. C'est de l'excellent livre CLR via C # par Jeffrey Ritcher . Sur la photo, les métadonnées dont il parle est la métadonnée émise dans l'en-tête d'assemblage où toutes les informations sur les types à l'Assemblée sont stockées:

JIT image from CLR via C#

15
Punit Vora

1) Tout en compilant le programme .NET, le code de programme .NET est converti en code langue 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 comme et lorsqu'une méthode est appelée; Ceci s'appelle la compilation JIT (juste à temps).

2
ravindranath