Java Language
Java Performance Tuning
Ricerca…
Approccio generale
Internet è pieno di suggerimenti per il miglioramento delle prestazioni dei programmi Java. Forse il consiglio numero uno è la consapevolezza. Questo significa:
- Identificare possibili problemi di prestazioni e colli di bottiglia.
- Utilizzare strumenti di analisi e test.
- Conoscere buone pratiche e cattive pratiche.
Il primo punto dovrebbe essere fatto durante la fase di progettazione se si parla di un nuovo sistema o modulo. Se si parla di codice legacy, gli strumenti di analisi e testing entrano in scena. Lo strumento più basilare per analizzare le tue prestazioni JVM è JVisualVM, che è incluso nel JDK.
Il terzo punto riguarda principalmente l'esperienza e la ricerca approfondita e, ovviamente, i suggerimenti grezzi che verranno visualizzati in questa pagina e altri, come questo .
Riduzione della quantità di stringhe
In Java, è troppo "facile" creare molte istanze String che non sono necessarie. Questo e altri motivi potrebbero far sì che il tuo programma abbia molte stringhe che il GC è impegnato a ripulire.
Alcuni modi in cui potresti creare istanze String:
myString += "foo";
O peggio, in un ciclo o ricorsione:
for (int i = 0; i < N; i++) {
myString += "foo" + i;
}
Il problema è che ogni +
crea una nuova stringa (di solito, poiché i nuovi compilatori ottimizzano alcuni casi). Una possibile ottimizzazione può essere fatta usando StringBuilder
o StringBuffer
:
StringBuffer sb = new StringBuffer(myString);
for (int i = 0; i < N; i++) {
sb.append("foo").append(i);
}
myString = sb.toString();
Se si costruiscono spesso stringhe lunghe (ad esempio SQL), utilizzare un'API di costruzione di stringhe.
Altre cose da considerare:
- Ridurre l'uso di
replace
,substring
ecc. - Evitare
String.toArray()
, specialmente nel codice di accesso frequente. - Le stampe di registro che sono destinate a essere filtrate (a causa del livello di registro per esempio) non dovrebbero essere generate (il livello di registro deve essere controllato in anticipo).
- Usa librerie come questa se necessario.
- StringBuilder è migliore se la variabile viene utilizzata in modo non condiviso (attraverso thread).
Un approccio evidence-based all'ottimizzazione delle prestazioni di Java
Donald Knuth è spesso citato come dicendo questo:
"I programmatori sprecano enormi quantità di tempo a pensare, o preoccuparsi, la velocità di parti non critiche dei loro programmi, e questi tentativi di efficienza in realtà avere un forte impatto negativo quando il debug e la manutenzione sono considerati. Dobbiamo dimenticare le piccole efficienze, dicono di Il 97% delle volte : l'ottimizzazione prematura è la radice di tutti i mali, tuttavia non dovremmo perdere le nostre opportunità in quel 3% critico ".
Tenendo presente questo consiglio, ecco la procedura consigliata per l'ottimizzazione dei programmi:
Prima di tutto, progetta e codifica il tuo programma o libreria con particolare attenzione alla semplicità e alla correttezza. Per cominciare, non spendere molto per le prestazioni.
Portalo a uno stato di lavoro e (idealmente) sviluppa test unitari per le parti chiave del codice base.
Sviluppare un benchmark delle prestazioni a livello di applicazione. Il benchmark dovrebbe coprire gli aspetti critici delle prestazioni della vostra applicazione e dovrebbe eseguire una serie di attività tipiche di come l'applicazione verrà utilizzata nella produzione.
Misura le prestazioni.
Confronta le prestazioni misurate con i tuoi criteri per la velocità con cui l'applicazione deve essere. (Evita criteri non realistici, irraggiungibili o non quantificabili come "il più velocemente possibile".)
Se hai soddisfatto i criteri, FERMA. Il lavoro è finito (Qualsiasi ulteriore sforzo è probabilmente una perdita di tempo.)
Profili l'applicazione mentre sta eseguendo il tuo benchmark delle prestazioni.
Esamina i risultati del profilo e scegli i "hotspot di prestazione" più grandi (non ottimizzati); cioè sezioni del codice in cui l'applicazione sembra passare più tempo.
Analizza la sezione del codice hotspot per cercare di capire perché è un collo di bottiglia e pensa a un modo per renderlo più veloce.
Implementalo come una proposta di modifica del codice, test e debug.
Rieseguire il benchmark per vedere se il cambio di codice ha migliorato le prestazioni:
- Se Sì, quindi tornare al passaggio 4.
- Se No, abbandonare la modifica e tornare al punto 9. Se non si stanno facendo progressi, selezionare un punto di attivazione diverso per l'attenzione.
Alla fine arriverete a un punto in cui l'applicazione è abbastanza veloce o avete preso in considerazione tutti gli hotspot significativi. A questo punto devi fermare questo approccio. Se una sezione di codice sta consumando (diciamo) l'1% del tempo complessivo, allora anche un miglioramento del 50% renderà l'applicazione solo dello 0,5% più veloce nel complesso.
Chiaramente, c'è un punto oltre il quale l'ottimizzazione dell'hotspot è uno spreco di energie. Se arrivi a quel punto, devi adottare un approccio più radicale. Per esempio:
- Guarda la complessità algoritmica dei tuoi algoritmi core.
- Se l'applicazione sta spendendo un sacco di tempo per la garbage collection, cerca modi per ridurre la velocità di creazione dell'oggetto.
- Se le parti chiave dell'applicazione sono ad uso intensivo della CPU e single-thread, cerca opportunità per il parallelismo.
- Se l'applicazione è già multi-thread, cerca i colli di bottiglia della concorrenza.
Ma ovunque sia possibile, affidati a strumenti e misure piuttosto che all'istinto per indirizzare i tuoi sforzi di ottimizzazione.