Java è davvero lento?


180

Java ha un certo grado di reputazione per essere lento .

  • Java è davvero lento?
  • Se si, perché? Dov'è (o era) il collo di bottiglia? È a causa di JVM inefficienti? Raccolta dei rifiuti? Librerie pure bytecode invece del codice C avvolto in JNI? Molte altre lingue hanno queste caratteristiche, ma non hanno questa reputazione per lentezza.

35
le persone diventano così nervose ... non vedo come questo può essere soggettivo, né è polemico. Mi chiedo se una domanda come "perché l'ordinamento delle bolle è lento" otterrebbe lo stesso risultato. Ho fatto una domanda tecnica e volevo risposte tecniche (che ho ottenuto), ma chiudere la domanda come soggettiva e argomentativa è ridicolo.
Stefano Borini,

1
Ho letto la maggior parte dei commenti principali e nessuno di questi sembra rispondere al fatto evidente che le applicazioni desktop basate su GUI C # funzionano molto più velocemente di qualsiasi applicazione desktop basata su GUI Java, comprese quelle moderne.
BobTurbo,

3
Come sviluppatore web lato client che si è occupato di moduli web .net, .net MVC, PHP, Rails, Django e un'ampia varietà di tutto tranne Spring (che ho sentito bene) in Java, mi aspetto prestazioni / architettura scadenti dai back end creati dai team Java. Sospetto che il vero problema non siano i parametri di riferimento, ma piuttosto il problema del fatto che ci sia semplicemente una stronzata di mediocri sviluppatori Java là fuori. Non è colpa della lingua. Non è colpa degli sviluppatori Java che realmente affinano il loro mestiere e imparano lingue diverse da Java. Potrebbe tuttavia essere colpa di Sun, Certs, degli anni '90 e del settore IT in generale.
Erik Reppen,

Risposte:


236

Java moderno è uno dei linguaggi più veloci, anche se è ancora un ricordo. Java aveva la reputazione di essere lento perché impiegava molto tempo per l'avvio della VM.

Se pensi ancora che Java sia lento , vedi i risultati del gioco dei benchmark . Il codice fortemente ottimizzato scritto in un linguaggio compilato in anticipo (C, Fortran, ecc.) Può batterlo; tuttavia, Java può essere più veloce di 10 volte rispetto a PHP, Ruby, Python, ecc. Esistono aree specifiche in cui può battere i linguaggi compilati comuni (se usano librerie standard).

Non ci sono scuse per le applicazioni Java "lente" adesso. Gli sviluppatori e il codice / le librerie legacy sono da biasimare, molto più della lingua. Inoltre, incolpare qualsiasi cosa "impresa".

In tutta onestà alla folla "Java è lento", ecco alcune aree in cui è ancora lento (aggiornato per il 2013):

  • Le librerie sono spesso scritte per "correttezza" e leggibilità, non per prestazioni. Secondo me, questo è il motivo principale per cui Java ha ancora una cattiva reputazione, soprattutto sul lato server. Ciò aggrava esponenzialmente i problemi di stringa. Alcuni semplici errori sono comuni: gli oggetti sono spesso usati al posto dei primitivi, riducendo le prestazioni e aumentando l'uso della memoria. Molte librerie Java (comprese quelle standard) creeranno frequentemente stringhe, anziché riutilizzare formati mutabili o più semplici (char [] o StringBuffer). Questo è lento e crea tonnellate di immondizia da raccogliere in seguito. Per risolvere questo problema, suggerisco agli sviluppatori di utilizzare raccolte primitive e in particolare le librerie di Javalution, ove possibile.

  • Le operazioni sulle stringhe sono un po 'lente. Java utilizza oggetti stringa immutabili con codifica UTF-16 . Ciò significa che hai bisogno di più memoria, più accesso alla memoria e alcune operazioni sono più complesse rispetto a ASCII (C, C ++). All'epoca, era la decisione giusta per la portabilità, ma comporta un piccolo costo in termini di prestazioni. UTF-8 sembra una scelta migliore ora.

  • L'accesso all'array è un po 'più lento rispetto a C, a causa dei controlli dei limiti. La penalità era grande, ma ora è piccola (Java 7 ottimizza molti controlli dei limiti ridondanti).

  • La mancanza di accesso arbitrario alla memoria può rallentare alcuni I / O e l'elaborazione a livello di bit (compressione / decompressione, ad esempio). Questa è una caratteristica di sicurezza della maggior parte delle lingue di alto livello ora.

  • Java utilizza MOLTA memoria in più rispetto a C, e se l'applicazione è associata alla memoria o alla larghezza di banda della memoria (memorizzazione nella cache, ecc.), Ciò rende più lento. Il rovescio della medaglia è che l'allocazione / deallocazione è velocissima (altamente ottimizzata). Questa è una caratteristica della maggior parte dei linguaggi di alto livello ora e grazie agli oggetti e all'uso di GC piuttosto che all'allocazione esplicita della memoria. Più decisioni sbagliate in biblioteca.

  • L'I / O basato su stream è lento a causa del fatto che (IMO, scelta errata) richiede la sincronizzazione su ciascun accesso allo stream. NIO ha risolto questo problema, ma è una seccatura da usare. Si può aggirare questo facendo lettura / scrittura su un array, anziché su un elemento alla volta.

  • Java non offre la stessa funzionalità di basso livello fornita da C, quindi non è possibile utilizzare trucchi di assemblaggio in linea sporchi per rendere più veloci alcune operazioni. Ciò fornisce portabilità ed è una caratteristica della maggior parte delle lingue di alto livello ora.

  • È comune vedere applicazioni Java legate a versioni JVM molto vecchie. Soprattutto lato server. Queste vecchie JVM possono essere incredibilmente inefficienti rispetto alle ultime versioni.

Alla fine, Java è stato progettato per fornire sicurezza e portabilità a spese di alcune prestazioni e per alcune operazioni davvero impegnative che mostra. La maggior parte della sua reputazione per lentezza non è più meritata.


Tuttavia, ci sono molti posti in cui Java è più veloce della maggior parte delle altre lingue:

  • L'allocazione e la disallocazione della memoria sono veloci ed economiche. Ho visto casi in cui è più veloce del 20% (o più!) Allocare un nuovo array multi-KB piuttosto che riutilizzarne uno memorizzato nella cache.

  • L'istanza e le funzionalità orientate agli oggetti sono incredibilmente veloci da usare (in alcuni casi più veloci del C ++), poiché sono progettate dall'inizio. Ciò è in parte dovuto al buon GC piuttosto che all'allocazione esplicita (che è più amichevole per molte allocazioni di piccoli oggetti). Si può codificare C che batte questo (rotolando la gestione della memoria personalizzata e facendo malloc in modo efficiente), ma non è facile.

  • Le chiamate al metodo sono sostanzialmente gratuite e in alcuni casi più veloci del codice di metodo grande. Il compilatore HotSpot utilizza le informazioni di esecuzione per ottimizzare le chiamate ai metodi e ha un allineamento molto efficiente. Utilizzando le informazioni aggiuntive sull'esecuzione, a volte può sovraperformare i compilatori anticipati e persino (in rari casi) l'inserimento manuale. Confronta con C / C ++ in cui le chiamate al metodo comportano una piccola penalità per le prestazioni se il compilatore decide di non inline.

  • La sincronizzazione e il multi-threading sono facili ed efficienti. Java è stato progettato per essere consapevole del thread sin dall'inizio e lo dimostra. I computer moderni di solito dispongono di più core e poiché il threading è integrato nella lingua, puoi trarne vantaggio facilmente. Fondamentalmente un aumento di velocità extra dal 100% al 300% rispetto al codice C standard a thread singolo. Sì, il threading e le librerie C attentamente scritti possono battere questo, ma questo è molto lavoro extra per il programmatore.

  • Le stringhe includono lunghezza: alcune operazioni sono più veloci. Questo batte usando stringhe delimitate da null (comune in C). In Java 7, Oracle ha eliminato l'ottimizzazione String.subString (), perché le persone lo utilizzavano stupidamente e ottenevano perdite di memoria.

  • La copia dell'array è altamente ottimizzata. Nelle ultime versioni, Java utilizza un assemblatore sintonizzato a mano per System.arraycopy. Il risultato è che nelle operazioni con arraycopy / memcopy pesanti, ho visto il mio codice battere l'equivalente in C con margini ragionevoli.

  • Il compilatore JIT è intelligente sull'uso della cache L1 / L2 . I programmi compilati in anticipo non possono modificare il loro codice in tempo reale sulla CPU e sul sistema specifici su cui sono in esecuzione. JIT fornisce alcune trasformazioni di loop molto efficienti in questo modo.

Un paio di altri fatti storici hanno contribuito alla reputazione "Java is slow":

  • Prima della compilazione JIT (Java 1.2 / 1.3), il linguaggio era solo interpretato, non compilato, e quindi molto lento.
  • La compilazione di JIT ha richiesto del tempo per diventare efficiente (importanti miglioramenti per ogni versione)
  • Il caricamento di classe è diventato molto più efficiente nel corso degli anni. Una volta era abbastanza inefficiente e lento durante l'avvio.
  • Swing e UI code non hanno usato molto bene l'hardware grafico nativo.
  • Swing è semplicemente orribile. Incolpo AWT e Swing per il motivo per cui Java non ha mai preso piede per il desktop.
  • Uso intenso della sincronizzazione nelle classi di libreria; sono ora disponibili versioni non sincronizzate
  • Il caricamento delle applet richiede un'eternità, a causa della trasmissione di un JAR completo sulla rete e del caricamento della VM per l'avvio.
  • La sincronizzazione ha comportato un forte calo delle prestazioni (questo è stato ottimizzato con ogni versione di Java). Tuttavia, la riflessione è ancora costosa.

49
Object instantiation and object-oriented features are blazing fast to use (faster than C++ in many cases) because they're designed in from the beginning.e Collections are fast. Standard Java beats standard C/C++ in this area, even for most optimized C code.sono affermazioni selvagge non supportate da alcuna prova collegata qui.
Sjoerd,

8
@Sjoerd - Le affermazioni non sono affatto selvagge - sono ovvie per me e dovrebbero essere per chiunque capisca le differenze nell'architettura del sistema di memoria predefinito in C / C ++ vs. Java. Si può fare molto meglio ancora se si scrive i propri gestori di memoria (con le cose come liste libere, pool di memoria e così via) o utilizzare una libreria che implementa tale.
Rex Kerr,

15
@Rex Kerr - Perché usare i gestori di memoria se puoi usare ad esempio lo stack per l'allocazione ?! Stai confondendo l'allocazione della memoria dell'heap con l'istanza dell'oggetto.
Sjoerd,

20
@Rex Kerr - Sostanzialmente lo stai sostenendo perché tutto in Java implica l'allocazione della memoria sull'heap e poiché l'allocazione di Java sull'heap in Java è più veloce di quella di C ++, tutto in Java è più veloce. Ecco alcune novità per te: in C ++ puoi fare a meno dell'allocazione di memoria sull'heap in molti casi!
Sjoerd,

10
@Sjoerd - Dove ho detto che tutto in Java è più veloce? Leggi solo quello che ho detto. Ho detto cosa volevo dire e ho già affrontato tutto ciò che hai detto nel tuo ultimo commento.
Rex Kerr,

49

Inizialmente Java non era particolarmente veloce, ma non è nemmeno troppo lento. In questi giorni, Java è molto veloce. Dalle persone con cui ho parlato, l'impressione che Java sia lento deriva da due cose:

  1. Tempo di avvio della VM lento. La prima implementazione di Java ha richiesto molto tempo per avviarsi e caricare le librerie richieste e l'applicazione rispetto alle applicazioni native.

  2. UI lenta. Early Swing è stato lento. Probabilmente non ha aiutato il fatto che la maggior parte degli utenti Windows trovasse brutta anche la versione predefinita di Metal L&F.

Dati i punti precedenti, non c'è da meravigliarsi che la gente abbia l'impressione 'Java è lento'.

Per gli utenti o gli sviluppatori abituati a sviluppare applicazioni native o anche applicazioni Visual Basic , questi due punti sono la cosa più visibile in un'applicazione ed è la prima impressione che otterrai su un'applicazione (a meno che non sia un'applicazione non GUI in cui caso vale solo 1.).

Non convincerai un utente che "esegue il codice molto velocemente" quando l'applicazione impiega 8 secondi per avviarsi rispetto alla sua vecchia applicazione Visual Basic che si avvia immediatamente, anche se l'esecuzione del codice e il tempo di avvio potrebbero non essere affatto connessi.

Rovinare la prima impressione è un ottimo modo per iniziare voci e miti. E voci e miti sono difficili da uccidere.

In breve, Java non è lento. Le persone che hanno "l'atteggiamento di Java è lento" si basano sulle prime impressioni di Java più di 10 anni fa.


3
Java è stato molto lento alcuni anni fa, ma nei recenti test di benchmark funziona quasi quanto C / C ++ e in alcune situazioni funziona più velocemente.
ChadNC,

23
Le app Java su OSX 10.6 sul mio Macbook si avviano molto più lentamente delle app scritte in Objective-C. Quali prove per tempi di avvio rapidi?
Zan Lynx,

2
La decompressione non è assolutamente un problema di prestazioni. Il mio computer nel 1992 ha decompresso gli eseguibili all'avvio di programmi che miglioravano le prestazioni rispetto al caricamento di un file più lungo dal disco rigido. La disparità tra CPU e disco rigido è cresciuta enormemente negli anni successivi. Tuttavia, c'è un problema con l'uso del formato di archivio zip per rt.jar (perché? !!!) e i file di classe contenuti non sono collegati (noci !!).
Tom Hawtin - tackline

5
@Zan: nota che JVM per Mac OS X è scritto (o almeno adattato) da Apple. Sun ha investito un po 'di tempo per accelerare i tempi di avvio sulle piattaforme che supportano (Windows, Linux e Solaris), ma non potevano farlo per Mac OS x (poiché non mantengono quella porta). È possibile che Mac non sia riuscito / non abbia applicato / trasferito tutte quelle ottimizzazioni su Mac OS X.
Joachim Sauer

1
Non considero java lento (conosco un creatore di giochi che crea giochi in essi); semplicemente male per motivi di interfaccia utente. Non una sola app java "normale" che ho visto ha un'interfaccia utente decente e completamente funzionante.
RCIX

40

Dopo aver letto una pagina piena di commenti che dicono che Java non è lento, devo solo rispondere con un'opinione diversa.

La lentezza di una lingua dipende molto dalle tue aspettative di "veloce". Se consideri C # veloce, anche Java è sicuramente veloce. Se il tuo dominio problematico è legato ai database o all'elaborazione semi-in tempo reale, anche Java è sicuramente abbastanza veloce. Se sei felice di ridimensionare la tua applicazione aggiungendo più hardware, Java è probabilmente veloce per te. Se consideri che un fattore di accelerazione costante nella scala di 5-10 non ne vale la pena, probabilmente consideri Java veloce.

Se si esegue il calcolo numerico su insiemi di dati di grandi dimensioni o si è vincolati a un ambiente di esecuzione, in cui le risorse della CPU sono limitate, in cui una velocità costante nella scala 5-10 sarebbe enorme. Anche una velocità di 0,5 potrebbe significare una riduzione di 500 ore per il completamento del calcolo. In questi casi, Java non ti consente di ottenere quell'ultimo metro di prestazioni e probabilmente considereresti Java lento.


2
d'accordo, e +1 su tutto il post perché presenti un punto valido, tuttavia, C ++ per esempio ha la diversa fama di essere difficile da eseguire il debug e di farti saltare in aria tutta la gamba, ma raramente ho sentito che C ++ è lento tanto come ho sentito di java.
Stefano Borini,

33

Sembra che tu stia facendo due domande piuttosto diverse:

  1. Java è davvero lento, e se sì perché?
  2. Perché Java è percepito come lento, anche se è più veloce di molte alternative?

Il primo di questi è più o meno un tipo di domanda "quanto è lunga una corda". Dipende dalla tua definizione di "lento". Rispetto a un interprete puro, Java è estremamente veloce. Rispetto ad altre lingue che sono (normalmente) compilate in una sorta di bytecode, quindi compilate dinamicamente in codice macchina (es. C # o qualsiasi altra cosa su .NET) Java è approssimativamente alla pari. Rispetto ai linguaggi che sono normalmente compilati al puro codice macchina, e hanno (spesso grandi) team di persone che non lavorano altro che migliorare i loro ottimizzatori (ad esempio C, C ++, Fortran, Ada) Java fa abbastanza bene in alcune cose, ma nel complesso tende ad essere almeno un po 'più lento.

Gran parte di questo è legato principalmente all'implementazione - fondamentalmente, si riduce al fatto che un utente è in attesa mentre è in esecuzione un compilatore dinamico / JIT, quindi a meno che tu non abbia un programma che gira da un po 'per iniziare, è difficile giustificare il fatto che il compilatore impieghi molto tempo su difficili ottimizzazioni. Pertanto, la maggior parte dei compilatori Java (e C #, ecc.) Non si impegna molto in ottimizzazioni davvero difficili. In molti casi, è meno su ciò che le ottimizzazioni vengono eseguite, rispetto a dove vengono applicate. Molti problemi di ottimizzazione sono NP completi, quindi il tempo necessario aumenta rapidamente con l'attacco delle dimensioni del problema. Un modo per mantenere il tempo entro limiti ragionevoli è applicare l'ottimizzazione a qualcosa come una singola funzione alla volta. Quando è solo lo sviluppatore in attesa del compilatore, puoi permetterti di impiegare molto più tempo e applicare la stessa ottimizzazione a blocchi molto più grandi del programma. Allo stesso modo, il codice per alcune ottimizzazioni è piuttosto peloso (e quindi può essere piuttosto grande). Ancora una volta, poiché l'utente sta aspettando il caricamento di quel codice (e il tempo di avvio di JVM è spesso un fattore significativo nel tempo complessivo), l'implementazione deve bilanciare il tempo risparmiato in un posto rispetto a quello perso in un altro - e dato quanto poco codice beneficia delle ottimizzazioni pelose, mantenere di piccole dimensioni la JVM è generalmente più vantaggioso.

Un secondo problema è che con Java si ottiene spesso una soluzione più o meno "a misura unica". Ad esempio, per molti sviluppatori Java Swing è essenzialmente l' unica libreria di finestre disponibile. In qualcosa come C ++, ci sono letteralmente dozzine di librerie di finestre, framework di applicazioni, ecc. Ognuno con il proprio set di compromessi tra facilità d'uso vs. esecuzione veloce, aspetto coerente vs aspetto nativo e così via. L'unico vero punto critico è che alcuni (ad es. Qt) possono essere piuttosto costosi (almeno per uso commerciale).

Terzo, un sacco di codice scritto in C ++ (e C ancora di più) è semplicemente più vecchio e più maturo. In gran parte contiene un nucleo di routine scritte decenni fa, quando passare del tempo in più per ottimizzare il codice era un comportamento normale, previsto. Ciò ha spesso un reale vantaggio nel codice più piccolo e più veloce. C ++ (o C) ottiene il merito che il codice è piccolo e veloce, ma è molto più un prodotto dello sviluppatore e i vincoli del tempo in cui il codice è stato scritto. In una certa misura, questo porta a una profezia che si autoavvera: quando le persone si preoccupano della velocità, spesso scelgono C ++ perché ha quella reputazione. Hanno dedicato ulteriore tempo e sforzi all'ottimizzazione e viene scritta una nuova generazione di codice C ++ veloce.

Riassumendo, la normale implementazione di Java rende al massimo problematica la massima ottimizzazione. Peggio ancora, dove Java è visibile , cose come i toolkit per finestre e il tempo di avvio di JVM spesso svolgono un ruolo maggiore della velocità di esecuzione del linguaggio stesso. In molti casi, C e C ++ ottengono anche credito per ciò che è veramente il prodotto del semplice lavorare di più per l'ottimizzazione.

Per quanto riguarda la seconda domanda, penso che sia in gran parte una questione di natura umana al lavoro. Alcuni fanatici fanno affermazioni piuttosto gonfie sul fatto che Java sia accecantemente veloce. Qualcuno lo prova e scopre che anche un programma banale impiega alcuni secondi per iniziare e si sente lento e goffo quando funziona. Pochi probabilmente si preoccupano di analizzare le cose per rendersi conto che gran parte di questo è il tempo di avvio della JVM e il fatto che quando provano le cose per la prima volta, nessuno del codice è stato ancora compilato - parte del codice viene interpretato, e alcuni vengono compilati mentre aspettano. Peggio ancora, anche quando corre abbastanza veloce, l'aspetto e la sensazione di solito sembrano estranei e goffi per la maggior parte degli utenti, quindi anche se le misurazioni obiettive mostrassero tempi di risposta rapidi, sembrerebbe comunque goffo.

L'aggiunta di questi insieme porta a una reazione abbastanza semplice e naturale: Java è lento, brutto e goffo. Dato l'hype che dice che è davvero veloce, c'è una tendenza a reagire in modo eccessivo e concludere a pensarlo orribilmente lento, invece di un (più accurato) "leggermente più lento, e questo principalmente in circostanze specifiche". Questo è generalmente il peggiore per uno sviluppatore che scrive i primi programmi nella lingua. L'esecuzione di un programma "ciao mondo" nella maggior parte delle lingue appare istantanea, ma in Java c'è una pausa facilmente percettibile all'avvio della JVM. Anche un puro interprete che gira molto più lentamente su loop stretti e che apparirà spesso più veloce per codice come questo, semplicemente perché può essere caricato e iniziare a eseguire un po 'prima.


16

Sono informazioni obsolete dei primi giorni (da metà alla fine degli anni '90) di Java. Ogni versione principale di Java ha introdotto importanti accelerazioni rispetto alla versione precedente. Con Oracle che sembra fondere JRockit con Sun JVM per Java 7, questa tendenza sembra destinata a continuare.

Rispetto a molti altri linguaggi moderni popolari (Python, Ruby, PHP), Java è in realtà significativamente più veloce per la maggior parte degli usi. Non corrisponde esattamente a C o C ++ ma per molte attività è abbastanza vicino. Le vere preoccupazioni relative alle prestazioni dovrebbero riguardare la quantità di memoria utilizzata.


14

Il principale colpevole del "lungo tempo di avvio" è il collegamento dinamico. Un'applicazione Java è composta da classi compilate. Ogni classe fa riferimento ad altre classi (per tipi di argomenti, invocazioni di metodi ...) per nome . La JVM deve esaminare e abbinare quei nomi all'avvio. Lo fa in modo incrementale, facendo solo le parti di cui ha bisogno in un dato momento, ma è ancora del lavoro da fare.

In un'applicazione C, quella fase di collegamento si verifica alla fine della compilazione. È lento, specialmente per le grandi applicazioni, ma solo lo sviluppatore lo vede. Il collegamento produce un file eseguibile che il sistema operativo deve semplicemente caricare nella RAM "così com'è".

In Java, il collegamento si verifica ogni volta che viene eseguita l'applicazione. Da qui il lungo tempo di avvio.

Sono state applicate varie ottimizzazioni, tra cui le tecniche di memorizzazione nella cache, e i computer diventano più veloci (e diventano "più veloci" delle applicazioni "più grandi"), pertanto l'importanza del problema è molto ridotta di recente; ma il vecchio pregiudizio rimane.

Per quanto riguarda le prestazioni successive, i miei benchmark su calcoli compatti con accessi ad array (principalmente funzioni di hash e altri algoritmi crittografici) di solito mostrano che il codice C ottimizzato è circa 3 volte più veloce del codice Java; a volte C è solo il 30% più veloce di Java, a volte C può essere 4x più veloce, a seconda dell'algoritmo implementato. Ho visto un fattore 10x quando il codice "C" era effettivamente assemblato per aritmetica di interi di grandi dimensioni, a causa dei codici operativi di moltiplicazione 64x64-> 128 che il processore offre ma Java non può usare perché il suo tipo intero più lungo è il 64-bit long. Questo è un caso limite. In condizioni pratiche, I / O e le considerazioni di larghezza di banda di memoria impediscono codice C da essere realmente tre volte più veloce di Java.


Hmm ... Pensavo che la maggior parte delle librerie C fosse collegata dinamicamente anche al giorno d'oggi. O stai parlando di qualcosa di diverso?
Sean McMillan,

4
@Sean: il collegamento dinamico per C si verifica per "simboli esterni": le funzioni utilizzate in una DLL e definite in un'altra. Un'applicazione C tipica utilizzerà una dozzina di DLL. Per Java il collegamento dinamico si verifica per tutti i metodi in tutte le classi: ce ne sono migliaia in un'applicazione Java tipica (inclusa la libreria standard). Nel mondo C, la maggior parte dei collegamenti (tutti i collegamenti che non attraversano un limite DLL) vengono risolti al momento della compilazione, solo una piccola parte rimane ancora da eseguire in fase di esecuzione.
Thomas Pornin,

14

Java è decisamente lento, specialmente per il lavoro quantitativo.

Uso una combinazione di R , Python e C / C ++ con librerie ATLAS multithread ottimizzate . In ognuna di queste lingue posso moltiplicare una matrice di 3000 per 3000 di doppie con se stessa in circa 4 secondi. Usando Colt e Parallel Colt in Java, la stessa operazione richiede 185 secondi! Sorprendente nonostante queste librerie Java siano di natura parallela.

Quindi, tutto sommato, Java puro non è adatto per il lavoro quantitativo. Jblas sembra essere la migliore libreria di algebra lineare per Java in quanto utilizza ATLAS.

La mia macchina è un HP Core 2 Duo con 3 GB di RAM. Uso Ubuntu 10.04 a 64 bit (Lucid Lynx).


In seguito al mio commento di cui sopra, ho eseguito la stessa operazione di moltiplicazione della matrice usando JAMA e ci sono voluti circa 50 secondi. Ancora troppo lento rispetto ad altre lingue.
Hamaad Shah,

7
Quanto tempo impiegava Java a eseguire la moltiplicazione nei libraire chiamati via JNI. Dato che qualsiasi cosa tu possa fare in C / C ++, puoi fare con JNI (aggiungere qualche centinaio di secondi) il margine è relativamente piccolo. Immagino che la tua moltiplicazione della matrice R e Python non sia stata scritta in R o Python, appena chiamata da quelle lingue.
Peter Lawrey,

2
Per curiosità, hai fatto qualche profilazione per identificare se hai qualche hotspot nel tuo codice (digita conversione / autoboxing)?
Thorbjørn Ravn Andersen,

10

Per l'esperienza della maggior parte delle persone che interagisce con esso - Java è lento. Abbiamo visto tutti quella tazza di caffè che gira sul nostro browser prima che arrivi qualche applet. Ci vuole un po 'di tempo per girare su JVM e scaricare i file binari dell'applet, e questo ha un impatto sull'esperienza dell'utente in un modo che si nota.

Non aiuta che il lento tempo di spin-up e download dell'applet JVM sia evidentemente marchiato con una tazza di caffè Java, quindi le persone associano l'attesa a Java. Quando Flash impiega molto tempo a caricarsi, il marchio del messaggio "caricamento" viene specificato dallo sviluppatore Flash, quindi le persone non danno la colpa alla tecnologia Flash nel suo insieme.

Tutto ciò non ha nulla a che fare con le prestazioni di Java su un server o in molti altri modi in cui Java viene utilizzato al di fuori del browser. Ma è ciò che la gente vede e ciò che gli sviluppatori non Java ricordano quando pensano a Java.


9

Java ha la reputazione di essere lento perché era lento. Le prime versioni di Java avevano compilation Just In Time assente o piuttosto scadente. Ciò significava che il codice, sebbene bytecode, veniva interpretato, quindi anche per le operazioni più semplici (come l'aggiunta di due numeri interi) la macchina doveva fare tutti i tipi di confronti, dereferenze puntatore e chiamate di funzioni. Il compilatore JIT è stato in costante miglioramento; ora è nel punto in cui se scrivo il codice C ++ con noncuranza e il codice Java con noncuranza, a volte Java supererà il C ++ perché il compilatore JIT si rende conto che ho un dereferenziamento del puntatore non necessario e se ne occuperà per me.

Se vuoi vedere quanta differenza fa la compilazione JIT, dai un'occhiata ai benchmark interpretati rispetto a quelli non interpretati nel Computer Language Benchmark Game . (Pidigits utilizza una libreria esterna per eseguire tutti i calcoli, in modo che il benchmark non cambi; gli altri mostrano una velocità 6-16x!)

Quindi, questo è il motivo principale. Esistono molte altre ragioni minori che non sono state utili: in origine, il tempo di avvio di Java era lento (ora risolto); il download di app Web in Java richiede molto tempo (molto meno vero ora con banda larga ampiamente accessibile e con grandi cose come i film attesi); l'interfaccia utente Swing non è stata (e non è ancora) scritta tenendo conto delle prestazioni, quindi è molto meno scattante rispetto agli equivalenti, ad esempio in C ++.


6

Java era lento, indietro nel tempo. È diventato molto più veloce, a causa di alcune generazioni di miglioramenti delle prestazioni . L'ultima volta che ho sentito, di solito è entro il 10% della velocità C # - a volte più veloce, a volte più lento.

L'avvio dell'applet Java è ancora lento perché devi avviare un'intera JVM, che deve caricare tutte le sue classi. Un po 'come l'avvio di un altro computer. Una volta avviato JVM è abbastanza veloce, ma l'avvio è di solito quello che la gente ricorda.

Inoltre, ci sono almeno alcune persone che non crederanno mai nella fattibilità di Java.


1
L'avvio di JVM è ancora molto più lento dell'avvio di CLR, sfortunatamente. Questo perché Sun ha trascinato i piedi nel modo peggiore nel rilasciare Java 7, quindi siamo bloccati con patch incrementali al Java 6. di 4 anni
BobMcGee,

3
Wow, Java 6 ha 4 anni ??? Sì, credo di si (se conti la beta). Mi sento ancora nuovo per me - ho appena smesso di usare 1.4 al lavoro.
Kaleb Brasee,

Java 1.4 è utilizzabile, ma un po 'succhiale, poiché 1.5 e 1.6 hanno aggiunto molti miglioramenti delle prestazioni e zucchero sintattico. Da allora sono state introdotte le ottimizzazioni di Bounds-check e System.arraycopy. Quindi sono stati apportati molti miglioramenti alla sincronizzazione. Penso che sia giusto dire che 1.4 è veramente lento.
BobMcGee

LOL, lo so - ogni volta che devo iterare manualmente o utilizzare un array anziché un elenco generico, voglio dividere il mio laptop a metà ... IBM ha effettivamente Java 5 disponibile su WAS 6.1 per anni, ma io ' sono stato bloccato su WAS 6.0 :( Sto usando Java 5/6 da quando è uscito per le mie cose, ma sono solo limitato dalle vecchie versioni del server al lavoro. Ci sono miglioramenti delle prestazioni percentuali a due cifre dall'1,4 alle versioni più recenti per molte cose, e non vedo l'ora di vederle.
Kaleb Brasee,

6

Stefano:

Sono stato con Java sin dall'inizio, quindi dal mio punto di vista la fama di essere lento è stata creata da front-end GUI (AWT e Swing) non reattivi e lenti e probabilmente in Applet a causa dei tempi di avvio lenti aggiuntivi del VM.

Java ha stipulato e promosso molte ricerche nell'area VM, e ci sono stati alcuni miglioramenti, tra cui la garbage collection (in realtà puoi mettere a punto molte cose; tuttavia, spesso vedo sistemi in cui vengono utilizzati solo i valori predefiniti) e hotspot ottimizzazione (che all'inizio e probabilmente è ancora più efficiente sul lato server).

Java a livello di backend e livello computazionale non è così lento. Colt è uno dei migliori esempi:

L'ultima versione stabile di Colt rompe la barriera 1.9 Gflop / s su JDK ibm-1.4.1, RedHat 9.0, 2x IntelXeon@2,8 GHz.

Ci sono molte cose al di fuori di Java tradizionale che dovrebbero essere considerate, come Realtime Java o meccanismi speciali per migliorare la velocità come Javolution , così come la compilazione Ahead-Of-Time (come gcj). Inoltre, ci sono IC che possono eseguire direttamente il bytecode Java, come ad esempio quello presente negli attuali iPhone e iPod ARM Jazelle .

Penso che generalmente oggi sia una decisione politica (come nessun supporto Java su iPhone / iPod) e una decisione contro Java come linguaggio (perché molti pensano che sia troppo prolisso).

Tuttavia, al giorno d'oggi ci sono molte altre lingue per la VM Java (ad esempio Python, Ruby, JavaScript, Groovy, Scala ecc.) Che possono essere un'alternativa.

Personalmente continuo a godermelo come una piattaforma flessibile e affidabile, con strumenti eccellenti e disponibilità di librerie, che consente di lavorare con qualsiasi dispositivo, dal più piccolo dispositivo (ad es. JavaCard) ai server più grandi.


Ok, quindi un'altra cattiva reputazione è venuta dal toolkit della GUI. Ovviamente suppongo che, poiché la moderna JVM utilizza widget nativi, si agganciano alle librerie del sistema operativo, giusto? o usano AWT / Swing per rendere lo stesso aspetto della piattaforma host?
Stefano Borini,

Stefano: Swing si basa in realtà sull'idea del rendering universale non nativo dei widget, quindi il tuo presupposto è un po 'sbagliato. È in effetti un meccanismo "innestabile" che consente ai componenti Swing di emulare l'aspetto dei componenti nativi. Se stai cercando qualcosa del genere, potresti provare SWT ( eclipse.org/swt ), che si collegherà effettivamente al sistema operativo nativo e utilizzerà i widget nativi usando JNI (che si dice sia un collo di bottiglia).
Dieter,

Java2D (utilizzato per Swing) è molto veloce in questi giorni e l'utilizzo di widget nativi (SWT) non offre alcun vantaggio in termini di prestazioni. Almeno, è quello che ho letto quando ho deciso se imparare Swing o SWT 6 mesi fa.
Luigi Plinge,

4

Un martello è molto più lento a stendere la pasta rispetto a molti altri strumenti. Non rende il martello "più lento", né meno utile per i compiti per cui è progettato.

Come linguaggio di programmazione generale, Java è alla pari con molti (se non la maggior parte) per una vasta gamma di attività di programmazione. Esistono test specifici e banali per i quali Java non supererà le soluzioni codificate a mano in linguaggi meno sofisticati, quelli che sono "più vicini al metal".

Ma quando si tratta di "applicazioni del mondo reale", Java è spesso lo strumento giusto. Ora, detto ciò, nulla impedisce agli sviluppatori di realizzare una soluzione a basse prestazioni utilizzando QUALSIASI strumento. L'uso improprio dello strumento è un problema ben noto (basta guardare la reputazione di PHP e VB). Tuttavia, il design pulito e la sintassi (principalmente) di Java fanno molto per ridurre l'uso improprio.


3

Java è un linguaggio di alto livello e la sua reputazione al giorno d'oggi è quella di avere prestazioni alla pari con altri linguaggi di alto livello comparabili.

  1. Ha una semantica di associazione dinamica . Rispetto al C ++ in cui i metodi non virtuali vengono compilati come chiamate di funzione, anche il miglior compilatore Java al mondo deve produrre codice meno efficiente. Ma è anche un semantico più pulito e di alto livello.

  2. Non ricordo i dettagli, ma ai primi tempi di Java ho sentito che c'era un mutex per oggetto Java, da acquisire e rilasciare con ciascun metodo. Ciò tende a renderlo più adatto alla concorrenza, anche se sfortunatamente solo un mutex per oggetto non ti proteggerà da razze o deadlock o da nessuna delle cose brutte che possono accadere in programmi simultanei. Quella parte, se vera, è un po 'ingenua, ma proviene da buone intenzioni. Sentitevi liberi di compilarmi sui dettagli se ne sapete di più su questo aspetto.

  3. Un altro modo in cui Java è un linguaggio di alto livello è avere Garbage-Collection . Garbage-Collection potrebbe essere più lento di malloce freeper i programmi che allocano immediatamente tutta la memoria di cui hanno bisogno e lavorano con quello. Il problema è che, nei linguaggi che non hanno Garbage Collection, i programmatori tendono a scrivere solo programmi che allocano tutta la memoria di cui hanno bisogno in una volta e falliscono se si scopre che è stata traboccata una costante di dimensione massima arbitraria. Quindi il confronto è dalle mele alle arance. Quando i programmatori si sforzano di scrivere ed eseguire il debug di programmi con allocazione dinamica di strutture concatenate in linguaggi non GC, a volte scoprono che i loro programmi non sono più veloci che in un linguaggio GC, perché mallocefreenon sono liberi! Hanno anche un sovraccarico ... Inoltre, non avere una forza GC per specificare chi libera cosa e dover specificare chi libera cosa a sua volta ti costringe a fare copie - quando diverse funzioni avranno bisogno dei dati e non è chiaro quale lo userà per ultimo, mentre la copia non sarebbe stata necessaria in un linguaggio GC.


1. Probabilmente non è vero con HotSpot. 2. Solo se si contrassegna il metodo come sincronizzato.
Winston Ewert,

1
1. Il compilatore non ottimizza il codice, ma JVM è abbastanza intelligente da determinare in modo dinamico solo uno o due metodi virtuali in genere chiamati e possono chiamarli staticamente o addirittura incorporarli. Sono abbastanza sicuro che C ++ non possa incorporare metodi virtuali. 2. Ogni oggetto Java ha un lucchetto. Ha un piccolo overhead (circa un byte) su ogni oggetto ma ha poco impatto se non utilizzato. 3. In Java è possibile allocare contemporaneamente tutti gli oggetti necessari. Questo può darti un'applicazione can che non GC tutto il giorno. ;) Il GC di Java è implicitamente multi-thread, qualcosa che richiede librerie speciali in C ++.
Peter Lawrey,

Il C ++ può incorporare le chiamate virtuali, ma Java può farlo in più casi ed è anche più forte con l'ottimizzazione dei siti di chiamata megamorfici.
Piotr Kołaczkowski

2

A metà degli anni Novanta, quando Java raggiunse il mainstream, il C ++ era il linguaggio dominante e il web era ancora abbastanza nuovo. Inoltre, JVM e GC erano concetti relativamente nuovi nello sviluppo tradizionale. Le prime JVM erano un po 'lente (rispetto al C ++ in esecuzione su bare metal) e soffrivano anche di pause a volte lunghe per la raccolta dei rifiuti, che portavano a una reputazione di Java lento.


era dovuto alla tecnologia alla base del GC? So che hanno alcune strategie (come i livelli generazionali per gli oggetti) per essere più efficienti nella fase GC. Qual era la strategia in quel momento?
Stefano Borini,

1
Esperto di IANA JVM, ma penso che all'epoca esistesse un algoritmo mark / sweep a thread singolo utilizzato per GC, che richiedeva l'interruzione dell'intera JVM durante l'esecuzione del GC. Oggi ci sono mark / sweep simultanei e ci sono anche molti altri miglioramenti delle prestazioni nella JVM.
Ken Liu,

2
I moderni algoritmi GC sono belli ma penso che il miglioramento più grande sia stato JIT.
Pascal Thivent,

1

Molte app desktop Java (questi tempi: cose come Eclipse) hanno una cattiva reattività della GUI, probabilmente a causa dell'elevato consumo di memoria e del fatto che classloader può fare un sacco di IO. Sta migliorando ma è peggiorato qualche anno fa.

Molte (la maggior parte) persone amano fare generalizzazioni, quindi dicono "Java è lento" perché percepiscono che le app sono lente quando interagiscono con loro.


pensi che l'elevato consumo di memoria provenga dallo strumento o dalle librerie Java?
Stefano Borini,

Nel caso di Eclipse, dall'infrastruttura stessa di Eclipse. Lo stesso vale per le GUI "pesanti" in passato (JBuilder come lo ricordo). Ho la sensazione che sia perché molti oggetti boilerplate sono necessari per usare un'architettura plugin (come Eclipse) in un linguaggio tipicamente statico. Emacs ha anche plugin e il suo consumo di memoria è 10-20 volte inferiore a Eclipse quando si esegue la codifica tipica. Il codice Emacs Lisp viene compilato in bytecode e caricato nell'istanza di emacs, quindi eseguito - in modo simile al classloader Java. Immagino che in Java ci siano tonnellate di oggetti intermedi istanziati per consentire una certa connettività.
Wojciech Kaczmarek,

1

Il problema principale con le applicazioni Java è che è enorme a causa delle grandi dimensioni della libreria di runtime di magazzino. Programmi enormi riempiono molto la memoria e tendono a scambiarsi, nel senso che diventano lenti.

Il motivo per cui Sun JVM è grande è perché ha un ottimo interprete di codici byte che funziona tenendo traccia di molte cose. Ciò significa molti dati, che significa memoria.

Potresti voler guardare la macchina virtuale jamvm che è un interprete abbastanza veloce (nessun codice nativo) e molto piccolo. Si avvia anche velocemente.


1

Come dice Pascal, Java è alla pari con altri linguaggi di alto livello. Tuttavia, come qualcuno che ha lavorato con le JVM originali su Windows 98 , al momento il livello di astrazione fornito dalla macchina virtuale Java era, per così dire, doloroso.

Fondamentalmente, era l'emulazione del software con poca o nessuna ottimizzazione che diamo per scontato oggi nella JVM.


0

Le persone normalmente trottano la linea "è interpretata". Perché una volta lo era, e la cattiva stampa viene tramandata da persone che hanno scaricato Java come "troppo lento" e non sono mai tornati per testare versioni più recenti.

O forse "le persone sono idioti" è una risposta migliore.


0

Penso che un giorno, forse non nel prossimo futuro, i linguaggi compilati da JIT supereranno i linguaggi compilati in qualsiasi aspetto (beh, forse non il tempo di avvio / consumo di memoria) a causa del fatto che i compilatori JIT possono fare un uso pesante del runtime comportamento e piattaforma su cui sono in esecuzione.


6
Penso che intendi dire che il codice compilato da JIT (non interpretato) supererà il codice AoT. L'interpretazione sarà sempre più lenta dell'esecuzione del codice compilato. Ecco perché vengono utilizzati i compilatori JIT. Il problema: c'è una piccola differenza tra un compilatore in anticipo e un compilatore JIT in termini di output, tranne per il fatto che un compilatore JIT deve compilare più rapidamente e può utilizzare le informazioni di runtime per suggerire le sue ottimizzazioni. I compilatori AoT specifici della piattaforma con ottimizzazioni specifiche della piattaforma batteranno quasi sempre JIT perché non vi è alcun limite al tempo dedicato all'ottimizzazione.
BobMcGee

Grazie per la risposta, non ho mai pensato al poco tempo a disposizione dei compilatori JIT.
helpermethod

vuoi dire, qualcosa come l'ottimizzazione adattiva hotspot?
Stefano Borini,

2
@BobMcGee: Molto bene. Un programma C ++ può essere creato per funzionare lentamente con feedback del profilo per tutte le sue operazioni. Quindi il compilatore è libero di ricostruire una versione molto veloce usando mezz'ora di CPU e 2 GB di RAM. Una SIC che avrebbe fatto uscire gli utenti.
Zan Lynx,

1
Il tempo di compilazione JIT è trascurabile per le app di lunga durata come i server. AOT con PGO è più limitato rispetto a JIT per almeno 2 motivi. Innanzitutto, la maggior parte delle differenze di prestazioni è raggiunta da ottimizzazioni leggere. Confronta gcc -O2 con gcc -O3. Il più delle volte non c'è differenza , a volte -O3 può essere leggermente migliore, a volte leggermente peggio, ma non ho mai avuto una differenza> 2x da questo. In secondo luogo, usando AOT anche con PGO puoi solo indovinare quale sarà il profilo sul sito di utilizzo. Indovina, e sei molto indietro rispetto alla squadra. E il profilo reale può essere estremamente dipendente dalla configurazione.
Piotr Kołaczkowski
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.