2010-12-23 4 views
13

Eventuali duplicati:
JIT compiler vs offline compilersquando java è più veloce di C++ (o quando JIT è più veloce, quindi precompilato)?

ho sentito dire che in determinate circostanze, i programmi Java o meglio parti di programmi Java sono in grado di essere eseguiti più velocemente di quanto il codice "stesso" in C++ (o altro codice precompilato) a causa dell'ottimizzazione JIT. Ciò è dovuto al fatto che il compilatore è in grado di determinare l'ambito di alcune variabili, evitare alcuni condizionali e trarre trucchi simili in fase di esecuzione.

Potresti fornire un esempio (o meglio alcuni) dove questo si applica? E forse delineare le condizioni esatte in cui il compilatore è in grado di ottimizzare il bytecode oltre quanto è possibile con il codice precompilato?

NOTA: Questa domanda è non sul confronto tra Java e C++. Riguarda le possibilità di compilazione JIT. Per favore non fiammeggiare. Inoltre non sono a conoscenza di duplicati. Per favore, indicali se lo sei.

+0

questo risulta essere in realtà un duplicato. Ci dispiace per l'inconvenienza. si prega di unire – kostja

risposta

33

In pratica, è molto probabile trovare il codice Java scritto ingenuamente outperform il codice scritto ingenuamente C++ in queste situazioni (ognuno dei quali ho personalmente osservato):

  • sacco di piccoli allocazioni di memoria/deallocazioni. Le JVM principali hanno sottosistemi di memoria estremamente efficienti e la garbage collection può essere più efficiente rispetto a richiedere la liberazione esplicita (in più può spostare gli indirizzi di memoria e così se lo desidera).

  • Accesso efficiente attraverso gerarchie profonde di chiamate di metodo. La JVM è molto brava a eliminare tutto ciò che non è necessario, solitamente meglio della mia esperienza rispetto alla maggior parte dei compilatori C++ (inclusi gcc e icc). In parte ciò è dovuto al fatto che può eseguire analisi dinamiche in fase di esecuzione (ad esempio, può sovrastimare e solo deottimizzare se rileva un problema).

  • Incapsulamento di funzionalità in piccoli oggetti di breve durata.

In ogni caso, se si mette lo sforzo, C++ può fare di meglio (tra le liste libere e block-allocato/memory deallocato, C++ può battere il sistema di memoria JVM in quasi ogni caso specifico; con codice aggiuntivo , modelli e macro intelligenti, è possibile comprimere gli stack di chiamate in modo molto efficace e si possono avere piccoli oggetti parzialmente allocati allo stack in C++ che superano il modello a oggetti di breve durata della JVM). Ma probabilmente non vuoi mettere lo sforzo.

+1

grazie. questo è il livello di dettaglio che speravo. – kostja

5

Wikipedia: http://en.wikipedia.org/wiki/Just-in-time_compilation#Overview

Inoltre, può in alcuni casi offerta prestazioni migliori rispetto compilazione statica, come molte ottimizzazioni sono fattibile solo in fase di esecuzione:

  1. La compilazione può essere ottimizzata per la CPU di destinazione e il modello di sistema operativo in cui viene eseguita l'applicazione. Ad esempio, JIT può scegliere le istruzioni della CPU SSE2 quando rileva che la CPU le supporta. Per ottenere questo livello di specificità di ottimizzazione con un compilatore statico, è necessario compilare un binario per ogni piattaforma/architettura prevista, oppure includere più versioni di porzioni del codice all'interno di un singolo binario.

  2. Il sistema è in grado di raccogliere statistiche di come il programma è effettivamente in esecuzione in un ambiente che è in, e può riordinare e ricompilare per un'ottimale prestazioni. Tuttavia, alcuni compilatori statici possono anche inserire informazioni di profilo come input.

  3. Il sistema può fare ottimizzazioni di codice globale (ad esempio inlining di funzioni di libreria) senza perdere i vantaggi di collegamento dinamico e senza spese generali inerenti compilatori statici e linker. Nello specifico, quando si eseguono sostituzioni in linea globali, un processo di compilazione statica potrebbe richiedere i controlli di runtime e assicurarsi che si verifichi una chiamata virtuale se la classe effettiva dell'oggetto sostituisce il metodo inline e potrebbero essere necessarie verifiche delle condizioni al contorno sugli accessi di array. essere elaborati all'interno di loop. Con la compilazione just-in-time in molti casi questa elaborazione può essere spostata da loop, spesso con grandi aumenti di velocità.

  4. Sebbene questo sia possibile con i linguaggi raccolti in modalità raccolta staticamente compilati, un sistema bytecode può più facilmente riordinare codice eseguito per un migliore utilizzo della cache.

+3

Ottime informazioni, ma la lettura da vicino rivela che la precompilazione in realtà può e fa molte delle ottimizzazioni "solo JIT". –

+1

@ BenVoigt Questo è un buon punto. L'argomento principale rimanente è che la JIT ha accesso a informazioni specifiche per il processo in esecuzione, anziché un profilo pre-creato o simile. Pertanto, può eseguire in grassetto le ottimizzazioni più frequentemente e con maggiori possibilità di successo. –

6

Alcuni esempi:

  • Il compilatore JIT può produrre codice macchina molto specifico della CPU utilizzando ad esempio le nuove estensioni SSE che non si useranno nel codice precompilato che deve eseguire una vasta gamma di CPU.
  • Il JIT sa quando un metodo virtuale (il default in Java) non viene sovrascritto da nessuna parte, e quindi può essere inline (anche se ciò richiede la possibilità di annullarlo quando viene caricata una nuova classe che sovrascrive il metodo; I compilatori Java JIT lo fanno in realtà).
  • Correlato a ciò, escape analysis consente diverse ottimizzazioni specifiche della situazione.
+0

Il primo punto è valido anche per quante librerie Java sono state scritte prima che fossero disponibili nuove architture della CPU. Queste vecchie librerie utilizzano ancora gli ultimi miglioramenti CPu. Per utilizzare l'ultima architettura in C++ devi essere in grado di compilare da sorgenti che molti non sono possibili/pratici con le librerie di terze parti. esp. se lo sviluppatore non è l'utente finale. per esempio. si dispone di un'applicazione che deve essere distribuita su molti diversi tipi di PC, può essere un incubo liberare tutte le piattaforme possibili in modo da scegliere spesso il più basso denomiatore comune. –

+0

Credo che il JIT possa eseguire l'inlining polimorfico. io.e conosce fino a due possibili metodi "virtuali" che vengono solitamente chiamati e questi possono essere sottolineati e se l'oggetto non è una di queste classi c'è un ripiego. Ciò significa che anche i metodi virtuali con più implementazioni possibili possono essere sottolineati in base al comportamento di runtime. –

+1

Gli ottimizzatori guidati dal profilo C++ usano questi stessi trucchi. –

0

La gestione della memoria di Java è considerevolmente più veloce di C++. Vedi Java theory and practice: Urban performance legends, revisited.

+0

un buon collegamento a volte è buono come una risposta può ottenere. molto perspicace. grazie – kostja

+5

Bel argomento uomo di paglia. C++ non richiede l'uso di 'malloc', si veda ad esempio l'allocatore di pool di wireshark. –

+0

quindi l'argomento non si applica all'allocazione C++ con nuovo allora? È perché l'heap assegnato da HeapAlloc e allo stesso modo viene utilizzato per l'allocazione con nuovo? – kostja