Perché .NET VM è basato? [duplicare]

15

Java è stato progettato per funzionare su una macchina virtuale per consentire la portabilità dei programmi.

Tuttavia .NET è stato progettato fin dall'inizio specificamente per Windows.

Quale è il motivo per cui le applicazioni .NET vengono compilate in bytecode per CLR?

È stato semplicemente copiare Java? O c'è un vantaggio tecnico nella compilazione nativa?

    
posta Aviv Cohn 28.09.2015 - 10:15
fonte

4 risposte

37

La compilazione di alcuni bytecode è una vecchia tradizione. Il codice P di UCSD esisteva nel 1978 e aveva molti precursori. Oggi LLVM può essere visto come un bytecode, targato da Clang / LLVM suite di compilazione in anticipo e GCCJIT può essere visualizzato come JIT correlato a GCC (con GIMPLE sorta di bytecode interno .

(quindi, bytecode, JIT, ... ha un significato abbastanza sfumato oggi: il senso più ampio di JIT è la compilazione all'interno del processo che esegue il codice compilato.)

Il bytecode JVM era inizialmente implementato come interprete. Ma Java è diventato abbastanza popolare da ottenere le JIT basate su JVM (e Sun ha investito molto nella tecnologia JIT, quindi questo ha aiutato Java ad avere successo)

E il JIT esisteva molto tempo fa (nei primi anni '80, ad esempio nelle macchine Lisp, e persino nel 1960 su CAB 500 computer e altri), prima ancora che fosse usato il nome. Molte implementazioni Common Lisp o Smalltalk hanno compilatori JIT (e oggi SBCL è completamente JIT-ing).

Nella mia comprensione, Microsoft ha progettato il codice bytecode CLR per essere compilato JIT (quindi ha ottenuto diversi compromessi nel suo codice byte rispetto alla JVM). Ed ha recentemente pubblicato la sua implementazione come software open-source e portato su Linux (prima di questo, Mono esisteva su Linux).

Un bytecode è spesso più compatto degli eseguibili nativi binari , può essere reso portatile per diverse architetture (ad es. x86 32 bit e x86-64 e anche ARM 32 bit, ARM / Aarch64, ...) e potrebbero essere progettati per evitare (o almeno ammorbidire) inferni di dipendenza .

Un grande vantaggio della compilazione JIT è che la VM può ricompilare alcune parti del bytecode sulla base di informazioni contestuali dinamiche (ad es. profilazione, introspezione dello stack di chiamate , ...) un po 'di codice. Alcune infrastrutture JIT come libjit , asmjit , LLVM , GCCJIT , ... non farlo (tuttavia, l'implementazione che li utilizza potrebbe farlo ricorrendo all'infrastruttura JIT-ing), ma la maggior parte delle implementazioni JVM o CLR industriali lo fanno (e alcune persone chiamano solo JIT quella compilazione dinamica pigra su richiesta, per me JIT è solo una parola d'ordine per la compilazione dinamica in fase di runtime). Questo è difficile o impossibile con compilazione AOT (almeno richiede LTO ), ed è impossibile se vuoi fare profile- ottimizzazione guidata dinamicamente a runtime (come si dice la maggior parte delle implementazioni JIT JVM o CLR). Inoltre, una VM bytecode non ha bisogno di compilare JIT tutto il bytecode, ma solo le parti più utilizzate (come HotSpot fa) e continua a interpretare il codice freddo usato raramente.

Anche le implementazioni JIT possono cooperare molto di più (e meglio ...) con sofisticati garbage collector .

PS. Non so nulla di Windows. Non l'ho mai usato Sto usando Linux dal 1994 e Unix dal 1987.

    
risposta data 28.09.2015 - 10:20
fonte
23

Windows non è una piattaforma singola e omogenea. Quando è stata rilasciata la prima versione di clr, è stata presa di mira non solo la tradizionale famiglia di sistemi Windows 98 (che funzionava solo su x86) ma anche Windows nt 4 (x86, ppc, alpha, mips). Il supporto per windows ce (che funzionava su x86, sh, arm, mips e ppc) è stato aggiunto nella versione 1.1, mentre i ia64 ("itanium") e gli obiettivi x86-64 su nt sono stati aggiunti nella versione 2. È molto probabile che il gli sviluppatori sapevano che la maggior parte o tutte queste piattaforme avrebbero dovuto essere supportate all'avvio del progetto. In effetti, sembra probabile che il fatto che gli ISV non volessero supportare questa moltitudine di piattaforme hardware e tendesse a rilasciare solo versioni x86 di applicazioni nella decisione di microsoft di andare avanti con lo sviluppo del sistema.

    
risposta data 28.09.2015 - 11:04
fonte
9

Eric Lippert ha una buona spiegazione del perché i linguaggi .NET abbiano come target IL invece di generare direttamente file binari intitolati Perché IL? .

Il motivo è che il costo / lo sforzo di sviluppare il compilatore è più economico / semplice con questo approccio. Il tuo compilatore di linguaggi di alto livello genera un linguaggio intermedio comune. Ciò semplifica l'aggiunta di nuove lingue poiché esiste solo una piattaforma per la generazione del codice. Poi hai i tuoi compilatori di seconda fase che prendono questo linguaggio intermedio e generano il binario specifico della piattaforma (OS e architettura della CPU).

In questo modo ogni volta che aggiungi il supporto per una nuova piattaforma (come un nuovo processore), devi solo scrivere un singolo compilatore che compili IL sulla nuova piattaforma.

    
risposta data 29.09.2015 - 00:28
fonte
2

Molte funzionalità del sistema di tipo .NET, in particolare i tipi generici che sono stati aggiunti alla 2.0 ma (da quello che ho capito) anticipati dal get-go, rendono letteralmente impossibile compilare il codice per tutti i tipi che un programma potrebbe utilizzare prima che inizi l'esecuzione (poiché le combinazioni di tipo utilizzate da un programma possono essere influenzate in modo arbitrario dagli input ricevuti da un programma e anche se il numero di tipi discreti effettivamente usati da un programma nel corso di una singola esecuzione deve essere limitato, il numero di tipi che un programma può utilizzare in risposta a vari input non deve essere). Mentre la generazione del codice dinamico è possibile anche senza una macchina virtuale, l'utilizzo di una macchina virtuale lo rende molto più semplice e sicuro.

Inoltre, l'efficienza della garbage collection in un ambiente multi-thread può essere migliorata enormemente dando al garbage collector la possibilità di bloccare simultaneamente tutti i thread che potrebbero fare qualsiasi uso di riferimenti a oggetti garbage-collected. Anche se il garbage collector è necessario per mantenere gli eventi "stop-the-world" il più breve possibile, la capacità del collector di bloccare unilateralmente altri thread dall'interazione con i riferimenti GC rende possibile per altri thread leggere e scrivere riferimenti senza dovendo usare letture e scritture interbloccate. Questo può avere enormi effetti sull'efficienza.

La maggior parte di ciò che la VM .NET riesce a realizzare può essere eseguita senza utilizzare una VM, ma l'utilizzo di una VM offre enormi vantaggi in termini di sicurezza e prestazioni che superano di gran lunga gli aspetti negativi.

    
risposta data 29.09.2015 - 01:11
fonte

Leggi altre domande sui tag