2010-04-30 13 views
6

Sto eseguendo un server applicazioni su Linux a 64 bit con 8 core CPU e 6 GB di memoria.Ottimizzazione JVM (GC) per applicazione server ad alta risposta

Il server deve essere altamente reattivo.

Dopo alcune ispezioni ho scoperto che l'applicazione in esecuzione sul server crea una quantità enorme di oggetti di breve durata e ha solo circa 200 ~ 400 MB di oggetti di lunga durata (purché non vi siano perdite di memoria)

Dopo aver letto http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html uso queste opzioni JVM

-server -Xms2g -Xmx2g -XX:MaxPermSize=256m -XX:NewRatio=1 -XX:+UseConcMarkSweepGC 

risultati: GC minore assume 0.01 ~ 0,02 sec, il principale GC prende 1 ~ 3 sec GC minore accade costantemente.

Come posso migliorare ulteriormente o ottimizzare la JVM?

dimensioni heap maggiori? ma ci vorrà più tempo per GC?

più grandi NewSize e MaxNewSize (per le giovani generazioni)?

altro collettore? GC parallelo?

è una buona idea lasciare che il GC principale si svolga più spesso? e come?

risposta

7

Risultato: il GC minore prende 0.01 ~ 0.02 sec, il principale GC prende 1 ~ 3 secondi il minore GC succede costantemente.

A meno che non si stiano segnalando pause, direi che il raccoglitore CMS sta facendo ciò che gli è stato chiesto di fare. Per definizione, CMS utilizzerà una percentuale maggiore della CPU rispetto ai collettori Serial e Parallel. Questa è la penalità che paghi per i tempi di pausa bassi.

Se visualizzi da 1 a 3 secondi pause, direi che è necessario eseguire alcune regolazioni. Non sono esperto, ma sembra che si dovrebbe iniziare riducendo il valore di CMSInitiatingOccupancyFraction dal valore predefinito di 92.

L'aumento della dimensione dell'heap migliorerà il "throughput" del GC. Ma se il tuo problema è una lunga pausa, aumentando la dimensione dell'heap è probabile che peggiori il problema.

2

Potresti essere interessato a provare la bassa pausa Garbage-First collector anziché il mark-sweep simultaneo (anche se non è necessariamente più performante per tutte le raccolte, si suppone che abbia una peggiore ipotesi migliore). È abilitato da -XX:+UseG1GC e si suppone che sia davvero stupefacente, ma potresti volerlo dare una valutazione approfondita prima di usarlo in produzione. Si è probabilmente migliorata da allora, ma sembra essere stato un po 'bacato un anno fa, come si è visto in Experience with JDK 1.6.x G1 (“Garbage First”)

+0

Vorrei sottolineare che l'Azul Zing jvm in molti casi "è" più performante. Fanno GC dietro le quinte mentre l'app è in esecuzione. Roba molto interessante Di nuovo, non è gratuito, ma per coloro che desiderano eliminare la necessità di sintonizzare una JVM, questo può farlo. Penso che lo chiamino il loro collezionista C4 (concurrent, continuous, compaction, collector?). Un recente benchmark di Mike McCandless lo ha testato su Apache Lucene/Solr contro CMS. Grandi risultati in termini di scalabilità: http://blog.mikemccandless.com/2012/07/lucene-index-in-ram-with-azuls-zing-jvm.html L'ho seguito in quanto cambia il gioco –

1

È perfetto per la garbage collection eseguire in parallelo con il tuo programma, se hai un sacco di CPU, cosa che fai.

Quello che vuoi, è essere assolutamente certi che non ti imbatterai in uno scenario in cui la garbage collection mette in pausa il tuo programma principale.

Hai semplicemente provato a non indicare alcun flag tranne che dire che vuoi la VM del server (per Sun JVM), quindi metti il ​​tuo server sotto carico per vedere come si comporta?Solo allora puoi vedere, se ottieni qualche miglioramento, armeggiando con le opzioni.

1

Questo in realtà suona come un'app della produttività e probabilmente dovrebbe utilizzare il raccoglitore della velocità effettiva. Vorrei bilanciare la dimensione del nuovo gen rendendolo abbastanza grande da non GC troppo spesso e abbastanza piccolo da prevenire lunghe pause. 20 ms suona come un lungo GC secondario. Sospetto anche che il tuo spazio per i sopravvissuti sia troppo grande e che venga sprecato. Se non hai molto da sopravvivere alla vecchia generazione, non dovresti avere così tanto da sopravvivere ai tuoi GC minori.

Alla fine, dovresti usare jvmstat e VisualGC per avere un'idea di come la tua app utilizza la memoria.

2

Attento .... GC può essere un argomento peloso se non si è cauti. All'interno di qualsiasi runtime (JVM per Java/CLR per .Net) ci sono diversi processi che avvengono. In generale, c'è una ottimizzazione della memoria in fase iniziale (Young Generational Garbage Collection/Young Gen GC & Old Generational Garbage Collection/Old Gen GC). Il giovane gen gc si svolge regolarmente e viene comunemente attribuito alle pause/singhiozzi minori. La vecchia generazione gc è normalmente ciò che sta accadendo quando vedi le lunghe pause "ferma il mondo".

Perché potresti chiedere? Il motivo per cui si ottiene una pausa con il proprio runtime/JVM è che quando il runtime esegue la pulizia di Heap deve passare attraverso quella che viene chiamata una modifica di fase. Arresta i thread che eseguono l'applicazione per contrassegnare e scambiare i puntatori per ottimizzare la memoria disponibile. Yong gen è più veloce poiché rilascia principalmente oggetti temporanei. Il vecchio gen, tuttavia, valuta tutti gli oggetti presenti nell'heap e quando si esaurisce la memoria scatterà per liberare la memoria necessaria.

Perché la cautela? Il vecchio gen peggiora in modo esponenziale nel tempo di pausa più accumuli usi. a 2-4 GB nella dimensione totale dell'heap si dovrebbe andare bene su runtime moderni come Java 6 (JDK 1.6+). Una volta che vai oltre quella minaccia, vedrai aumenti esponenziali nei tempi di pausa. Ho incontrato alcuni client che devono riavviare i server, poiché in alcuni rari casi in cui un heap è di grandi dimensioni, i tempi di pausa in GC possono richiedere più tempo rispetto a un riavvio completo.

Ci sono alcuni nuovi strumenti là fuori che sono abbastanza interessanti e possono dare un vantaggio nella valutazione di GC è il tuo dolore. JHiccup è uno ed è gratuito dal sito web azulsystems. In questo momento penso che sia solo per Linux. Hanno anche una JVM che ha un algoritmo GC ricostruito che funziona senza pausare ... ma se si esegue una distribuzione su un singolo server con un'app non critica, potrebbe non essere conveniente (che non è gratuito).

Per riassumere - se il runtime/JVM/CLR heap è inferiore a 2 GB l'aggiunta più memoria sarà di aiuto. Assicurati di darti un po 'di spese generali. Se non è possibile, non si desidera toccare il 100% della dimensione dell'heap/dimensioni della memoria. Questo è quando le lunghe pause sono le più lunghe. Regalati un 20% in più di memoria su ciò che pensi di aver bisogno. In questo modo hai spazio per gli algoritmi GC per spostare gli oggetti in giro per l'ottimizzazione. Se hai intenzione di diventare grande ... c'è uno strumento che risolve la tecnologia JVM del 1990 circa (Azul Systems Zing JVM), ma non è gratuito. Offrono uno strumento open source per diagnosticare problemi di GC. La JVM (come ho provato) ha anche un davvero cool strumento di visibilità a livello di thread che consente di segnalare su eventuali perdite, insetti, o serrature in produzione senza spese generali (qualche trucco con scarico dati la JVM si occupa già con e marcatura temporale). Questo ha permesso di risparmiare un sacco di tempo per i test di sviluppo ... ma ancora, non per le piccole app.

Permanenza sotto di 4 GB. Dai spazio extra. E se si vuole si può attivare queste bandiere per monitorare GC per Java/JVM:

java -verbose:gc myProgram 
java -Xloggc:D:/log/myLogFile.log -XX:+PrintGCDetails myProgram 

si può provare alcuni degli altri collezionisti Hotspot utilizza. Ce ne sono più di uno

Se sei su Linux, vai avanti e prova anche lo strumento JHiccup. È gratis.

1

Per applicazioni server ad alta reattività, penso che si desideri vedere il GC più frequente con minore frequenza. Ecco l'elenco dei parametri potrebbe aiutare.

-XX: + CMSParallelRemarkEnabled
-XX: + CMSScavengeBeforeRemark
-XX: + UseCMSInitiatingOccupancyOnly
XX: CMSInitiatingOccupancyFraction = 50
XX: CMSWaitDuration = 300000
XX: GCTimeRatio = 40

Le dimensioni di heap più grandi potrebbero non essere d'aiuto in caso di bassa pausa, a condizione che l'app non esaurisca la memoria.

Più grandi NewSize e MaxNewSize potrebbero aiutare sulla velocità effettiva, potrebbe non essere d'aiuto in bassa pausa. Se scegli di adottare questo approccio, potresti considerare di dare ai thread GC più tempo di esecuzione impostando -XX: GCTimeRatio in basso. Il punto è ricordare di prendere una visione olistica durante la messa a punto di JVM.

0

Penso che i posters precedenti abbiano perso qualcosa di molto ovvio: la dimensione della Perm Generation è troppo bassa. Se il sistema utilizza da 200 a 400 MB come generazione permanente, allora è meglio impostare Max Perm Gen su 400 MB. anche la dimensione PerGen dovrebbe essere impostata sullo stesso valore. Non resterai mai a corto di spazio di generazione permanente.

Attualmente sembra che la JVM debba impiegare molto tempo a spostare oggetti dentro e fuori dalla Generazione permanente. Questo può richiedere tempo. JVM tenta di allocare aree di memoria contigue agli oggetti Java: questo accelera l'accesso alla memoria a causa delle funzionalità a livello di hardware. Per fare ciò, è molto utile avere un sacco di buffer in memoria. Se la Generazione permanente è quasi piena, gli oggetti permanenti scoperti di recente devono essere divisi o gli oggetti esistenti devono essere mescolati. Questo è ciò che attiva un GC completo, oltre a causare lunghe pause complete del GC.

La domanda afferma che la dimensione della Generazione permanente è già stata misurata, se non è stata eseguita, deve essere misurata utilizzando uno strumento. Questi strumenti elaborano i registri generati da JVM con l'opzione verboseGC attivata.

Tutte le opzioni di contrassegno e scansione sopra elencate potrebbero non essere necessarie con questo miglioramento di base.

Le persone lanciano le opzioni GC come soluzioni senza valutare in quale misura esse abbiano dimostrato di essere effettivamente utilizzate.

+0

Penso che tu sono confusi riguardo alla generazione permanente. Non contiene oggetti, contiene le definizioni di classe, i metadati di classe, ecc. –

Problemi correlati