2010-10-25 11 views
42

Esistono numerosi suggerimenti sulle prestazioni resi obsoleti dal compilatore Java e in particolare Profile-guided optimization. Ad esempio, queste ottimizzazioni fornite dalla piattaforma possono drasticamente (in base alle fonti) ridurre il costo delle chiamate alle funzioni virtuali. VM è anche in grado di eseguire l'allineamento dei metodi, lo srotolamento del loop, ecc.Consigli obsoleti per l'ottimizzazione Java

Quali sono le altre tecniche di ottimizzazione delle prestazioni che sono state ancora applicate ma che sono rese obsolete dai meccanismi di ottimizzazione presenti nelle JVM più moderne?

+0

Ho una taglia su una domanda correlata qui, se qualcuno ha delle citazioni per le risposte a questo: http://stackoverflow.com/questions/3963643/canonical-reference-on -jvm-internals-for-programmatore-sviluppatori – andersoj

+0

Sono caduto la domanda è difettosa perché dipende dal compilatore che si utilizza –

+0

Non imperfetto, solo "ampio". –

risposta

23

Il modificatore finale sui metodi e sui parametri del metodo non aiuta affatto le prestazioni.

Inoltre, lo Java HotSpot wiki offre una buona panoramica delle ottimizzazioni utilizzate da HotSpot e di come utilizzarle in modo efficiente nel codice Java.

+2

link carino, ma sembra che non parli di 'final'. Dice che "finale" è un suggerimento per l'inlining. Ho pensato che ci fossero casi in cui il modificatore finale assicurerebbe al compilatore che il suo valore non può cambiare in un ciclo anche se quel ciclo richiama altri metodi e oltre l'orizzonte corrente. – Will

+0

Vedere: http://stackoverflow.com/questions/3961881/why-defining-class-as-final-improves-jvm-performance – andersoj

+4

'final' su metodi (o classi per quella materia) non fornisce informazioni al JIT. Tuttavia, 'final' su un parametro del metodo potrebbe fornire utili suggerimenti di ottimizzazione (simile a una variabile locale dichiarata come finale). In definitiva, però, la ragione per usare final è forzare l'immutabilità - questa è una caratteristica del design-time per rendere il codice più facile da mantenere. Qualsiasi vantaggio di ottimizzazione dovrebbe essere a) preoccupato solo se ci fosse effettivamente un problema di prestazioni, e b) testato in modo esaustivo per garantire che effettivamente ha fatto la differenza. –

20

Persone che sostituiscono String a = "this" + var1 + " is " + var2; con più chiamate a StringBuilder o StringBuffer. In realtà utilizza già StringBuilder dietro le quinte.

+0

In questo caso, I credo che l'ottimizzazione si applichi ancora. Il codice di esempio che hai mostrato costruisce 3 distinte istanze di StringBuilder, una per ogni concatenazione; costruirne solo uno sarebbe (leggermente) più efficiente. Correggimi se sbaglio – RMorrisey

+3

Oh, pensavo che avrebbe fatto l'equivalente di 'String a = new StringBuilder (" this "). Append (var1) .append (" is "). Append (var2) .toString();'? –

+3

questa * unauthoriative * fonte http://www.rgagnon.com/javadetails/java-0129.html suggerisce che Paul ha ragione riguardo al singolo StringBuilder, ma dice che la capacità di default di StringBuilder può essere troppo breve (strano, sarebbe banale che un compilatore che impiega il tempo per usare un StringBuffer non si preoccupi di contare la capacità prima dell'uso) – Will

8

Nel 2001 ho creato app per un telefono J2ME. Era delle dimensioni di un mattone. E quasi il potere computazionale di un mattone.

Per far funzionare le app Java in modo accettabile è necessario scriverle nel modo più procedurale possibile. Inoltre, l'enorme miglioramento delle prestazioni è stato quello di catturare lo ArrayIndexOutOfBoundsException per uscire da loop su tutti gli elementi di un vettore. Pensaci!

Anche su Android ci sono cicli "veloci" attraverso tutti gli elementi in un array e modi "lenti" di scrivere la stessa cosa, come menzionato nei video IO di Google sugli interni di dalvik VM.

Tuttavia, in risposta alla tua domanda, direi che è molto insolito dover micro-ottimizzare questo tipo di cose in questi giorni, e mi aspetterei ancora che su un JIT VM (anche il nuovo Android 2.2 VM, che aggiunge JIT) queste ottimizzazioni sono discutibili. Nel 2001 il telefono eseguiva un interprete KVM a 33MHz. Ora esegue dalvik - una VM molto più veloce di KVM - a 500MHz a 1500MHz, con un'architettura ARM molto più veloce (un processore migliore che consente anche guadagni di velocità di clock) con L1 e.t.c. e JIT arriva.

Non siamo ancora nei regni in cui mi sentirei a mio agio nel manipolare direttamente i pixel in Java - sia sul telefono che sul desktop con un i7 - quindi c'è ancora un normale codice giornaliero che Java non è abbastanza veloce per Here's an interesting blog che afferma che un esperto ha affermato che Java è l'80% della velocità di C++ per un compito pesante della CPU; Sono scettico, scrivo codice di manipolazione delle immagini e vedo un ordine di grandezza tra Java e nativo per loop su pixel. Forse mi manca qualche trucco ...? : D

+1

Un po 'OT, ma per quanto riguarda le prestazioni, un mio amico ha creato una porta Doom fedele alla fonte in Java, e ottiene circa 130-145 FPS a risoluzione 640x480 su un singolo thread P4 @ 3GHz. Non OpenGL, solo blitting. –

+0

Sì, ma ho suonato Doom in modo accettabile su un 486 ... (tuttavia, il progetto del tuo amico sembra molto divertente e molto interessante) – Will

16

È necessario definire i compromessi di tempo/memoria prima di iniziare l'ottimizzazione delle prestazioni. Ecco come lo faccio per la mia memoria/applicazioni critiche tempo (ripetendo alcune risposte di cui sopra, per essere completa):

  1. Regola # 1 Mai fare l'ottimizzazione delle prestazioni in fase di sviluppo precedente. Non farlo mai se non ne hai davvero bisogno. Se hai deciso di farlo, allora:
  2. usa il profiler per trovare i colli di bottiglia, controlla il codice sorgente per trovare i motivi dei colli di bottiglia;
  3. scegliere la struttura dati appropriata con la migliore corrispondenza nei compromessi temporali/di memoria definiti;
  4. scegliere gli algoritmi appropriati (ad es.iterazione vs ricorsione, ecc.);
  5. evitare di utilizzare oggetti sincronizzati dalla libreria java, se non ne avete davvero bisogno;
  6. evitare esplicitamente/implicitamente la creazione di nuovi oggetti;
  7. ignora/reimplementa i tipi di dati/algoritmi forniti con java se e solo se si è certi che non soddisfano le proprie esigenze.
  8. Utilizzare test piccoli e indipendenti per verificare le prestazioni delle strutture di dati/alghe prescelti.
+2

Questi suggerimenti non sono veramente obsoleti. Voglio dire, è un consiglio brillante, ma non stai rispondendo alla domanda. –

+2

-1: non risponde a cosa viene chiesto. –

1
  1. "ottimizzazione prematura è la radice di tutti i mali" (Donald Knuth)
  2. E 'utile per ottimizzare solo i colli di bottiglia.
  3. È necessario analizzare il codice in ogni situazione. Forse puoi sostituire TreeSet con un HashSet veloce perché non hai bisogno della funzione di ordinamento o forse puoi usare float invece di double (guarda l'SDK di Android).
  4. Se nessuna tecnica ti aiuta puoi provare a riscrivere un pezzo di codice e chiamarlo tramite JNI, in modo che il codice nativo funzioni.
+6

-1 per la citazione che è sia incompleta che non pertinente alla domanda. Donald Knuth ha dichiarato: "Dovremmo dimenticare le piccole efficienze, diciamo circa il 97% delle volte: l'ottimizzazione prematura è la radice di tutti i mali" In secondo luogo la domanda riguarda le tecniche generali di ottimizzazione che non sono più applicabili, non c'è nulla da dimostrare che è prematuro, è una discussione generale – hhafez

4
  1. Non chiamare manualmente il garbage collector, fa male le prestazioni sulle moderne implementazioni di JVM.
  2. Integer anziché Long non salverà molto spazio, ma limiterà l'intervallo dei numeri.
  3. Evita le classi Enum generate manualmente e utilizza invece l'Enum incorporato. Java 1.5 ha introdotto veri Enum, li usa.
2

Quando si utilizza x64 JVM con meno di RAM 32 GB:

uso 64bit JVM 30% -50% più memoria in confronto a 32bit JVM a causa di grandi puntatori di oggetti ordinari. Puoi ridurre pesantemente questo fattore usando JDK6 +.

Da JDK6u6p a JDK6u22 è opzionale e può essere abilitata aggiungendo argomento JVM:

-XX:+UseCompressedOops 

Da JDK6u23 (JDK7 anche) si è attivata per impostazione predefinita. Maggiori informazioni here.