2010-10-01 5 views
20

Il titolo riassume molto ma mi chiedevo perché sistemi come .net compilano il codice ogni volta che viene eseguito invece di compilarlo una sola volta sul computer di destinazione?Perché .net usa un compilatore JIT invece di compilare il codice una sola volta sul computer di destinazione?

+0

La maggior parte delle risposte non ha letto attentamente la domanda. Sta chiedendo: perché la macchina di destinazione non può fare una volta la compilation e tenerla (non: perché non possiamo compilare una volta e distribuire il file binario) – egrunin

+1

Funziona già in questo modo. Guarda attraverso i servizi installati sul tuo computer. Il servizio "NGEN di Microsoft .NET Framework" entra in azione per la precompilazione degli assembly. Se opportunamente solleticato da un installatore. –

+1

Non si compila ogni volta che viene eseguito. Quando un metodo viene compilato con JIT, il codice nativo generato viene archiviato nella cache di immagini native. Nelle esecuzioni successive se il runtime vede che un metodo è già stato compilato, non lo ricompone di nuovo. – mhenry1384

risposta

22

Ci sono due cose che si possono ottenere utilizzando un formato intermedio come Java o .NET:

  1. È possibile eseguire il programma su qualsiasi piattaforma, proprio perché il codice è rappresentato in un formato intermedio invece di natale codice. Hai solo bisogno di scrivere un interprete per il formato intermedio.
  2. Esso consente per alcune ottimizzazioni di runtime che non sono (facilmente) possibile al momento della compilazione: per esempio, è possibile sfruttare le caratteristiche speciali sui nuovi processori, anche se non ci fossero queste CPU quando hai scritto il programma - solo il compilatore JIT deve saperlo.

Ora, per quanto riguarda il motivo per cui si potrebbe non voler eseguire la compilazione alla prima esecuzione e quindi solo memorizzarla nella cache - ci possono essere anche un paio di motivi.

Se si compila prima dell'avvio, l'utente deve attendere molto più tempo per quella prima esecuzione - in quel momento, non si può sapere cosa l'utente effettivamente utilizzerà. Compilando solo ciò di cui hai bisogno, quando ne hai bisogno, puoi iniziare molto più rapidamente, semplicemente perché hai meno lavoro da fare e non immagazzini tanto codice che l'utente non userà mai (che per un grande programma può essere un sacco di codice).

Se si avvia il caching del codice JIT attraverso le sessioni, è necessario tenere traccia di ciò che è già stato compilato e quindi memorizzarlo su disco. Per un programma di grandi dimensioni, potresti avere un sacco di codice nativo da caricare dal disco. I/O del disco sono piuttosto costosi, quindi potrebbe essere necessario più tempo per attendere il disco piuttosto che ridirigerlo. Inoltre, è necessario tenere traccia di quanto tempo è utilizzabile. Se l'hardware cambia, potresti voler re-JIT per applicare alcune nuove ottimizzazioni. Se il programma cambia, non puoi usare nessuno dei tuoi vecchi codici compilati. Se il compilatore di runtime cambia, potrebbe essere stato corretto un errore di sicurezza e sarà necessario ricompilare per assicurarsi che il bug non rimanga nel codice nativo.

Fondamentalmente, il compilatore JIT ha improvvisamente molto più lavoro da fare (incluso l'I/O del disco per gestire la cache) e diventa molto più complicato e lento, riducendo il punto di JIT'ing.

Ora, ciò non significa che a volte non sia vantaggioso compilarlo preconfigurato, e come sottolinea Matthew Ferreira, questo è ciò che lo strumento ngen può fare - ma nel caso generale, non è solo vale la pena farlo, perché la compilazione JIT è spesso più che abbastanza veloce.

+1

# 1 è probabilmente il singolo motivo più importante – STW

+4

Nessuno di questi punti è pertinente alla domanda: atli ha chiesto di compilarlo sul computer di destinazione, non sul computer dello sviluppatore. – JasonFruit

+1

@Jason: Ah, hai ragione - ho interpretato male quella parte. Modifica ... –

5

Cosa succede se si sposta l'eseguibile su un'altra macchina? Se fosse stato compilato una volta per il processore specifico della prima macchina, non sarebbe in grado di sfruttare un set di istruzioni (possibilmente) più avanzato o efficiente disponibile sul nuovo processore. Se si desidera compilare una volta sul computer di destinazione, considerare l'utilizzo di ngen.exe durante l'installazione dell'applicazione.

6

Non scrivo compilatori o run-time, quindi non posso dirlo con certezza, ma non credo che sia just-in-time = ogni volta. Significa solo che aspettiamo di aver davvero bisogno di compilare, ma una volta che la compilazione è stata fatta per quell'istanza, non verrà più compilata.

+1

Sei corretto: se un pezzo di codice non viene eseguito durante una sessione, non è necessario che sia compilato JIT. Tuttavia, il codice compilato JIT non è (solitamente) memorizzato nella cache per le sessioni future, quindi la compilazione JIT si ripeterà la volta successiva che si esegue il programma. –

+0

@ Michael Che non è corretto. NGen memorizza nella cache il codice compilato JIT per il riutilizzo futuro. –

0

Se si compila direttamente alla macchina di codice, allora hai scelto come target un sistema specifico:

 
Code --> Machine Code 

Tuttavia, in .NET, Java, etc.quello che stai prendendo di mira è la macchina virtuale . Questo produce codice che qualsiasi VM conforme a .NET può interpretare e, a sua volta, JIT in codice macchina reale.

Così, in .NET:

 
Code --> IL --> VM (executing) --> JIT'd Machine Code 

Inizialmente sembra più complicato, ma come targeting più architetture:

 
Code(x86) --> Machine Code(x86) 
Code(ppc) --> Machine Code(ppc) 
etc... (1x code-set per target) 

Versus

 
Code --> IL --> VM(x86) (executing) --> JIT'd x86 Machine Code 
       VM(ppc) (executing) --> JIT'd ppc Machine Code 
       etc... 

La mia illustrazione è ruvida, ma noterai che un singolo pacchetto di codice .NET può essere indirizzato e eseguito su più piattaforme

3

Un altro vantaggio della compilazione JIT: il codice che è stato scritto 10 o 15 anni fa può ottenere un significativo incremento delle prestazioni semplicemente eseguendo una JIT avanzata, senza alcuna modifica del codice.

+0

Tuttavia, CLR potrebbe facilmente includere un numero di versione nell'ipotetica versione JIT del cache memorizzata sul disco dell'assembly ed eliminarlo la prima volta che viene eseguito su un CLR aggiornato. – binki

2

Il titolo praticamente riassume, ma mi chiedevo perché sistemi come .net compilano il codice ogni volta che viene eseguito invece di compilarlo una sola volta sul computer di destinazione?

.NET fa cache i risultati di compilazione CIL in codice nativo su un determinato obiettivo, ma questo non è banale:

  • esiste un trade-off tra il caricamento nella cache i dati dal disco e ricompilare on- il volo.
  • Qualsiasi forma di generazione di codice in fase di esecuzione richiede la possibilità di compilare al volo. Questo non è solo l'uso di System.Reflection.Emit ma anche la reificazione dei tipi da assiemi caricati dinamicamente e anche la creazione di nuovi tipi di valore durante la ricorsione polimorfica.
+0

Il fatto che 'Expression .Compile()' esista (e qualsiasi altra cosa sia vagamente eval-like) in realtà è probabilmente uno dei più grandi motivi per avere un ottimo JIT. – binki

Problemi correlati