Perché sono necessarie le macchine virtuali?

8

Invece di compilare il codice sorgente per il rispettivo SO (sul quale è indirizzato), compili una volta ed esegui ovunque.

Per il gusto di questa domanda, la chiamerei VM (ad esempio, sia per Java che per .NET). Quindi questo l'esecuzione dei programmi diventa qualcosa come

 ------------       ----      ----
| Executable |  -> | VM | -> | OS |
 ------------       ----      ----

Ha perfettamente senso, il compilatore rimane generico per la rispettiva VM. Tuttavia, l'implementazione della VM può variare a seconda della macchina che verrà installata, ad esempio (* nix, windows, mac) x (32 bit, 64 bit).

La mia domanda è, invece di scrivere VM per le rispettive macchine, perché il compilatore non è scritto per quella macchina specifica? Con questo, invece di scaricare la rispettiva VM, si scarica il rispettivo compilatore e il compilatore si prenderà cura del codice macchina + OS per quella specifica macchina. Risultato finale, esecuzione di codice nativo per qualsiasi macchina. Sicuramente, ogni codice sorgente avrebbe bisogno di una compilazione per quella specifica macchina, ma ora un giorno, i sistemi automatici, le build scm possono aiutarci a fare questa cosa.

Le mie ragioni di essere confusi sono giuste o mi mancano alcuni aspetti tecnici qui?

Modifica:

PORTABILITÀ :

Sì, è una delle ragioni, ma la portabilità è un grosso problema nei sistemi automatici odierni? quanto spesso dobbiamo preoccuparci del fatto che non dobbiamo compilarlo per altre macchine? Avere un codice compilato per la macchina nativa darebbe prestazioni molto migliori. Prendi Java per esempio, non puoi fare programmazione a basso livello su Windows e devi scegliere JNI.

Assumi sistemi automatici come TeamCity / Jenkins o altri. Potremmo disporre di una tale configurazione automatica del sistema in cui il codice inviato tramite il controllo della versione risulterebbe nell'eseguibile.

    
posta Em Ae 19.04.2012 - 00:41
fonte

9 risposte

16

My question is, instead of writing VM for respective machines, why isn't the compiler written for that specific machine?

Perché allora non avresti più un eseguibile portatile; avresti un eseguibile per ogni piattaforma. L'utente dovrebbe scaricare un eseguibile specifico per la sua piattaforma, o compilare il codice da solo, sulla sua piattaforma specifica.

Con una VM, ogni piattaforma ha solo bisogno della sua VM specifica per piattaforma, quindi è possibile distribuire lo stesso eseguibile su ogni piattaforma.

    
risposta data 19.04.2012 - 01:03
fonte
12

Ti manca qualcosa di enorme con queste VM. Fanno esattamente quello che dici, ma automaticamente. È chiamato un compilatore Just-In-Time ed è per questo che .NET (su Windows) e Java sono estremamente vicini alla velocità del codice C ++ compilato in modo nativo.

Il codice sorgente Java / C # viene convertito in codice byte. Questo codice byte viene quindi compilato in codice macchina sulla macchina su cui è attualmente in esecuzione. Per la maggior parte, la VM eseguirà il codice nativo invece di rielaborare il codice byte.

Ho saltato un po 'e semplificato il processo, ma le VM fanno una notevole quantità di lavoro.

    
risposta data 19.04.2012 - 01:41
fonte
7

Come molti concetti in informatica, la VM fornisce un livello di astrazione. Scrivi il tuo codice contro una 'interfaccia' (codice byte / lingua intermedia) e il livello di astrazione (la VM) si occupa dei dettagli dell'implementazione (compilandolo per il computer di destinazione e altre attività.) Il livello di astrazione ti fornisce un set di servizi i cui particolari di implementazione non ti servono più. In questo caso, non è più necessario preoccuparsi delle specifiche dell'hardware sottostante, dato che sono presenti i servizi del livello di astrazione (VM). Il cliente beneficia in modo simile - non hanno bisogno di conoscere i dettagli sulla loro piattaforma, solo che possono usare il livello di astrazione.

Naturalmente, ci sono dei compromessi con qualsiasi astrazione. Si perde il controllo a grana fine sui dettagli sull'altro lato dell'astrazione e si deve fare affidamento su tale astrazione per impiegare un'implementazione ragionevole. È necessario considerare i potenziali guadagni attraverso l'uso di un'astrazione contro i trade-off. In alcune applicazioni gli svantaggi possono soppesare i vantaggi: potrebbe essere necessario un livello elevato di controllo per ogni piattaforma.

La tua proposta di utilizzare un sistema automatizzato per le compilazioni su piattaforme diverse è esattamente ciò che fanno già i livelli di astrazione .NET e Java. Uno dei vantaggi della compilazione JIT è che il compilatore ha dettagli specifici sulla macchina su cui è in esecuzione. Ciò può introdurre potenziali ottimizzazioni che altrimenti non sarebbero possibili quando si esegue una build di rilascio sul computer di uno sviluppatore.

Se si è preoccupati del rallentamento del tempo di esecuzione a causa della generazione del codice nativo e dell'esecuzione del programma che si verificano insieme, è possibile generare il codice nativo durante l'installazione piuttosto che quando il programma viene eseguito per la prima volta. .NET fornisce nGen a questo scopo, che può eseguire operazioni native generazione del codice al momento dell'installazione piuttosto che al tempo di esecuzione. Il CLR utilizzerà quindi il codice nativo memorizzato nella cache anziché eseguire la compilazione JIT.

    
risposta data 19.04.2012 - 04:34
fonte
3

Questo semplifica enormemente questo aspetto, la multipiattaforma è molto più di una semplice compilazione per uno specifico set di istruzioni native. Più comune di no, lo stesso codice C / C ++ non può essere ricompilato su piattaforme diverse perché le API: s e le librerie sono diverse. Ad esempio, lo sviluppo della GUI è molto diverso su Windows e Ubuntu Linux, la comunicazione socket probabilmente non è identica su Unix e IBM z / OS e così via.

Quindi, per ottenere il tuo "scrivi una volta, compila (e collega) ovunque", dovresti creare un livello di astrazione di alcuni tipi, dove crei un'API comune per tutti i livelli di OS Servizi. Quindi devi implementarlo e distribuirlo per tutte le piattaforme che vuoi supportare.

Inoltre, mentre i modelli di memoria sono oggi sempre più simili, ci sono ancora alcune differenze tra piattaforme diverse, quindi è necessario anche astrarre l'allocazione di memoria. È più facile qui forse creare il tuo gestore di memoria "virtuale" su quello nativo.

Mentre ci sei, i file system e il controllo degli accessi (ACL) sono gestiti in modo abbastanza diverso tra, ad esempio, Unix e Windows, quindi dovrai astrarre anche queste cose. Forse persino creare il proprio wrapper "File" per le implementazioni sottostanti.

Quindi abbiamo threading. Dal momento che Linux ha solo processi e Windows ha thread, dobbiamo in qualche modo astrarre anche questo.

Bene, a questo punto hai praticamente costruito una macchina virtuale. Il punto qui è che mentre la compilazione di codice arbitrario per diverse piattaforme è abbastanza semplice, costruire software di lavoro di qualsiasi complessità che può essere eseguita su qualsiasi piattaforma è tutt'altro che banale.

    
risposta data 19.04.2012 - 14:36
fonte
2

Un altro importante vantaggio dell'approccio VM / JIT è la compatibilità binaria. Ad esempio, supponiamo che tu abbia un assembly / JAR / DLL che contiene la classe A e un altro assembly che contiene la classe B, che deriva dalla classe A. Cosa succede se cambi la classe A, ad es. aggiungi un membro privato? L'aggiunta di un membro privato non dovrebbe avere alcuna influenza sulla classe B, ma se l'assembly che contiene B fosse già compilato in codice nativo, si otterrebbero probabilmente bug strani e arresti anomali difficili da riprodurre, perché il codice nativo è stato compilato con il vecchio layout di memoria di A, quindi per esempio riserva troppo poca memoria per le variabili di A, quindi i membri di A e i membri B aggiunti verrebbero mappati alle stesse posizioni di memoria.

Se si utilizza una macchina virtuale, d'altra parte, tutti questi problemi semplicemente svaniscono, perché quando il codice è compilato in codice nativo, il layout di tutte le classi è noto.

    
risposta data 19.04.2012 - 09:33
fonte
2

My question is, instead of writing VM for respective machines, why isn't the compiler written for that specific machine?

Immaginiamo per un secondo che questo è il modo in cui funziona. Scrivo un'applicazione Java, che poi compilo: il compilatore genera quindi un eseguibile per ogni piattaforma supportata. Ora ho i seguenti eseguibili:

  • Solaris x64
  • Solaris x86
  • Solaris SPARC
  • Windows x86
  • Windows x64
  • Linux x86
  • Linux x64
  • MacOS
  • BSD

etc etc.

Quindi li carico tutti sul mio sito Web e fornisco un link per il download a ciascuno di essi. Quindi invio tutti questi a download.com, tucows.com, sofpedia.com, inviandoli singolarmente.

Questo mi sembra un grosso problema! Quando aggiorno il software alla versione 1.1, devo ripetere questo processo.

E cosa succede quando emerge una nuova piattaforma? Ora il mio software non è disponibile per questa piattaforma, a meno che non aggiorni il mio software sviluppatore per supportarlo, ricompilare, quindi rilasciare nuovamente il software per questa nuova piattaforma.

E l'utente? Visitano il mio sito e quindi devono selezionare da un elenco la versione corretta del mio software da utilizzare per la loro piattaforma. La maggior parte degli utenti non sa se eseguono x86 o x64, quindi probabilmente finiranno per scaricare la versione sbagliata e ricevere qualche tipo di errore. Che cosa succede se passano da Windows a un Mac, ora devono tornare indietro e scaricare nuovamente il software.

Tutto questo è un grosso problema, sia per lo sviluppatore che per l'utente, e tutto ciò può essere evitato semplicemente compilandolo su un bytecode, quindi eseguendo una VM, esattamente come fa attualmente Java.

Se le prestazioni sono quasi identiche all'esecuzione del codice nativo, la domanda non è tanto il motivo per cui non è possibile compilare il codice nativo, piuttosto perché preoccuparsi di compilare il codice nativo?

    
risposta data 19.04.2012 - 10:16
fonte
1

Nella modifica del tuo post, ti interroghi sull'utilità della portabilità, wrt VM.

Nella mia vita professionale, la portabilità è stata il fattore più importante - La mia piattaforma di distribuzione è molto raramente la stessa piattaforma su cui dispiego, e quindi sono in grado di sviluppare e amp; prova su Windows, passa al mio dipartimento QA, chi testerebbe su Linux e distribuirà nel nostro ambiente di produzione su Solaris.

Questo non è solo un esempio isolato e forzato: questo è stato praticamente il pane della mia vita professionale probabilmente per gli ultimi 12 anni della mia carriera pluridecennale. Sono sicuro che ce ne sono molti altri con esperienze identiche o simili.

Se usassimo diversi compilatori (incrociati) (sullo stesso codice sorgente) per produrre binari diversi, non potevi sentirti sicuro della qualità di ciascun binario, se non fossero stati testati sul proprio sistema operativo / architettura.

Il meraviglioso progetto OpenPascal Compiler open source ha una riga di "write-once, compile anywhere" - mentre questo è vero, non mi aspetterei di vedere nessuna software house stimabile e rilasciare le applicazioni senza test approfonditi tutte le piattaforme.

    
risposta data 19.04.2012 - 12:06
fonte
1

Facile: test.

Se il codice funziona correttamente su Virtual Machine, puoi essere sicuro che funzionerà su un altro hardware che ha dimostrato di avere una VM funzionante.

Se compili per piattaforme diverse hai un sacco di test da fare, perché ogni piattaforma ha le sue peculiarità.

    
risposta data 19.04.2012 - 14:17
fonte
0

La portabilità è molto più di una semplice compilazione del codice!

Il comportamento di un programma C può essere diverso sulle piattaforme fidate:

int  i;
char c[6];
int * p;

p = &c[2];
p = p + 1;

Funziona senza reclami su un chip IBM Power, ma, tramite un'eccezione su un chip SPARC.

La versione del sistema operativo, del sistema operativo, le impostazioni del registro delle variabili d'ambiente del file system possono influenzare il modo in cui verrà eseguito un programma compilato.

Una JVM garantisce praticamente lo stesso comportamento indipendentemente dall'ambiente hardware e software.

    
risposta data 19.04.2012 - 12:30
fonte

Leggi altre domande sui tag