Domanda

Qual è la differenza tra il compilatore JIT e CLR? Se si compila il codice in il e CLR esegue quel codice, cosa sta facendo la JIT? Come è cambiata la compilazione JIT con l'aggiunta di generici al CLR?

È stato utile?

Soluzione

Il JIT è un aspetto del CLR.

In particolare è la parte responsabile della modifica di CIL / MSIL (di seguito chiamata IL) prodotta dal compilatore del linguaggio originale (ad esempio csc.exe per Microsoft c #) in codice macchina nativo del processore corrente (e architettura in cui è esposto il processo corrente, ad esempio 32/64 bit). Se l'assembly in questione è stato annullato, il processo JIT è completamente inutile e il CLR eseguirà questo codice bene senza di esso.

Prima di utilizzare un metodo che non è stato ancora convertito dalla rappresentazione intermedia, è responsabilità della JIT convertirlo.
Esattamente quando la SIC sarà specifica per l'implementazione e soggetta a modifiche. Tuttavia, il progetto CLR impone che JIT avvenga prima del codice pertinente, il JVM al contrario sarebbe libero di interpretare il codice per un po 'mentre un thread separato crea una rappresentazione del codice macchina.
Il CLR "normale" utilizza un approccio pre-JIT stub dove per metodi vengono compilati JIT solo quando vengono utilizzati. Ciò implica che lo stub del metodo nativo iniziale sia indiretto per indicare a JIT di compilare il metodo, quindi modificare la chiamata originale per saltare lo stub iniziale. L'attuale edizione compatta invece compila tutti i metodi su un tipo quando viene caricato.

Per affrontare l'aggiunta di Generics.

Questa è stata l'ultima grande modifica alle specifiche IL e JIT in termini di semantica rispetto ai dettagli di implementazione interna.

Sono state aggiunte diverse nuove istruzioni IL e sono state fornite più opzioni di metadati per tipi di strumenti e membri. I vincoli sono stati aggiunti anche a livello di IL.

Quando JIT compila un metodo che ha argomenti generici (esplicitamente o implicitamente attraverso la classe contenente), può impostare percorsi di codice diversi (istruzioni di codice macchina) per ciascun tipo usato. In pratica, la SIC utilizza un'implementazione condivisa per tutti i tipi di riferimento poiché le variabili per questi mostreranno la stessa semantica e occuperanno lo stesso spazio (IntPtr.Size).

Ad ogni tipo di valore verrà generato un codice specifico per esso, trattando la dimensione ridotta / aumentata delle variabili nello stack / heap è una delle ragioni principali di ciò. Inoltre, emettendo il codice operativo vincolato prima delle chiamate di metodo, molte invocazioni su tipi non di riferimento non devono necessariamente racchiudere il valore per chiamare il metodo (questa ottimizzazione viene utilizzata anche in casi non generici). Ciò consente inoltre di gestire correttamente il comportamento predefinito <T> e di eliminare i confronti con null come nessuna operazione (sempre falsa) quando si utilizza un tipo di valore non Nullable.

Se viene eseguito un tentativo in fase di runtime per creare un'istanza di un tipo generico tramite reflection, i parametri del tipo verranno convalidati dal runtime per garantire che superino eventuali vincoli. Ciò non influisce direttamente sul JIT a meno che non venga utilizzato all'interno del sistema di tipi (improbabile anche se possibile).

Altri suggerimenti

Compilate il vostro codice in IL che viene eseguito e compilato in codice macchina durante il runtime, questo è ciò che si chiama JIT.

Modifica , per arricchire ulteriormente la risposta (ancora eccessivamente semplificata):

Quando compili il tuo codice C # in Visual Studio, questo diventa IL che capisce il CLR, l'IL è lo stesso per tutte le lingue in esecuzione sopra il CLR (che è ciò che consente al runtime .NET di usare diverse lingue e inter-op tra di loro facilmente).

Durante il runtime l'IL viene interpretato nel codice macchina (che è specifico dell'architettura in cui ti trovi) e quindi viene eseguito. Questo processo è chiamato compilazione Just In Time o in breve JIT. Solo l'IL necessario viene trasformato in codice macchina (e solo una volta, è & Quot; cache & Quot; una volta compilato in machinecode), appena in tempo prima che venga eseguito, quindi il nome JIT.

Ecco come sarebbe C #

  

Codice C # > Compilatore C # <=> IL <=> .NET Runtime <=> Compilatore JIT <=> Codice macchina <=> Esecuzione

E questo è come apparirebbe per VB

  

Codice VB <=> Compilatore VB <=> IL <=> .NET Runtime <=> Compilatore JIT <=> Codice macchina <=> Esecuzione

E come puoi vedere solo i primi due passi sono unici per ogni lingua, e tutto ciò che è stato trasformato in IL è lo stesso che è, come ho detto prima, il motivo per cui puoi eseguire diverse lingue sopra. NET

Come dice Jon Skeet, JIT fa parte del CLR. Fondamentalmente questo è ciò che sta accadendo sotto il cofano:

  1. Il codice sorgente è compilato in un codice byte noto come linguaggio intermedio comune (CIL).
  2. I metadati di ogni classe e ogni metodo (e ogni altra cosa: O) sono inclusi nell'intestazione PE dell'eseguibile risultante (sia esso una dll o un exe).
  3. Se stai producendo un eseguibile, l'intestazione PE include anche un bootstrapper convenzionale che si occupa del caricamento del CLR (Common language runtime) quando esegui il tuo eseguibile.

Ora, quando esegui:

  1. Il bootstraper inizializza il CLR (principalmente caricando l'assembly mscorlib) e gli indica di eseguire l'assembly.
  2. Il CLR esegue la voce principale.
  3. Ora, le classi hanno una tabella vettoriale che contiene gli indirizzi delle funzioni del metodo, in modo che quando chiami MyMethod, questa tabella viene cercata e quindi viene effettuata una chiamata corrispondente all'indirizzo. All'avvio TUTTE le voci per tutte le tabelle hanno l'indirizzo del compilatore JIT.
  4. Quando viene effettuata una chiamata a uno di tali metodi, JIT viene invocato invece del metodo effettivo e assume il controllo. Il JIT quindi compila il codice CIL in un vero codice assembly per l'architettura appropriata.
  5. Una volta compilato il codice, la JIT entra nella tabella dei metodi vettoriale e sostituisce l'indirizzo con quello del codice compilato, in modo che ogni chiamata successiva non invochi più la JIT.
  6. Infine, JIT gestisce l'esecuzione del codice compilato.
  7. Se chiami un altro metodo che non è stato ancora compilato, torna a 4 ... e così via ...

La JIT è sostanzialmente parte del CLR. Il garbage collector è un altro. Piuttosto dove si mettono le responsabilità di interoperabilità ecc. È un'altra questione, e quella in cui sono enormemente sottoqualificato per commentare :)

So che il thread è piuttosto vecchio, ma ho pensato di poter inserire l'immagine che mi ha fatto capire JIT. Viene dall'eccellente libro CLR via C # di Jeffrey Ritcher . Nell'immagine, i metadati di cui sta parlando sono i metadati emessi nell'intestazione dell'assembly in cui sono archiviate tutte le informazioni sui tipi nell'assembly:

Immagine JIT da CLR via C #

1) durante la compilazione del programma .net, il codice del programma .net viene convertito in codice IL (Intermediate Language)

2) dopo aver eseguito il programma il codice di lingua intermedia viene convertito in codice nativo del sistema operativo come e quando viene chiamato un metodo; questa si chiama compilation JIT (Just in Time).

  1. Common Language Runtime (CLR) è interprete mentre Just In Time (JIT) è compilatore in .Net Framework.

2.JIT è il compilatore interno di .NET che prende il codice MSICL (MicroSoft Intermediate Code Language) da CLR e lo esegue per istruzioni specifiche della macchina mentre CLR funziona come motore il suo compito principale è fornire il codice MSICL a JIT per garantire quel codice è completamente compilato secondo le specifiche della macchina.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top