GC Tweaks

Ho letto sul sito della Sun un HowTo su come settare alcuni parametri
riguardanti la garbage collection in modo da renderla meno
“penalizzante” su sistemi che hanno vincoli stringenti in termini di
troughput o tempi di risposta. Provo a sintetizzare quel che mi è
parso di capire.

Non sono elencati tutti i parametri di “fine tuning” del
gc, nè tantomeno vengono spiegati tutti i principi di funzionamento
indicati nei documenti (che ho elencato in fondo a questo post) o i
casi in cui è meglio optare per una soluzione piuttosto che un’altra.
Ho seguito gli esempi presentati sul sito e mi sono occupato
principalmente delle ottimizzazioni maggiorimente utili per
applicazioni enterprise.

Se qualcuno ha avuto modo di sperimentare direttamente altre questioni
collegate alla configurazioni del garbage collection, sono benvenute
integrazioni (ho visto che nelle versioni più recenti di java esistono
altre opzioni, alcune però utilizzabili solo su macchine Solaris in
quanto vanno ad agire in modo strettamente correlato col sitema
operativo – es. si può decidere di non trasferire alcune pagine di
memoria su disco)

dalla jvm 1.3 in poi si possono usare 2 tipi di garbage collection

(a)- una è bloccante ma parallelizzabile (quindi su sistemi
multicore/multicpu scala bene). tale tipologia è anche chiamata
“throughput garbage collector”

(b)- una è composta di 4 fasi, 2 brevi e bloccanti e 2 più lunghe ma
concorrenti… può essere utile per migliorare i tempi di risposta, ma
non viene parallelizzato. anche noto come “concurrent garbage collector”

– per jre 1.4.2+ oltre ai collector “troughput” e “concurrent” esiste
il gc “incremental” (detto anche “train”)

il ciclo di vita di un oggetto, dalla creazione alla garbage
collection, passa attraverso 3 aree di memoria, su cui le policy di
garbage collection sono diverse
– eden
– young (o survivor)
– old

per gli oggetti che si trovano nello stato “old” viene adottata la
policy (b), per gli altri la (a)

ci sono diversi parametri per stabilire quando un’oggetto passa da
un’area di memoria all’altra e quanto l’intervento del gc deve essere
aggressivo, intendendo con cioò sia quanta (poco) spazio sull’heap
deve restare prima che il gc intervenga, quanto tempo debba essere
trascorso dall’ultima operazione di gc e quanto spazio si debba
effettivamente tentare di liberare.

benché la garbage collection resti un evento imprevedibile, a seconda
del contesto applicativo si possono comunque regolare questi parametri
al fine di avere interruzioni più brevi, menoi frequenti o comunque
meno bloccanti per l’applicazione

le opzioni sono

-XX:+UseParNewGC (jre 1.4.1+) parallelizzazione della GC per “young”
-ovvero la policy (a), può essere usato contemporaneamente alla policy
(b) per gli old
-XX:ParallelGCThreads=n che ritengo autoesplicativo e va settato al
numero di cpu o jvm sul sistema in uso
-XX:+UseParallelGC (jre 1.3+) viene usata esclusivamente la policy (a)
-XX:+CMSParallelRemarkEnabled da utilizzare per ridurre le pause nella
fase di remark (la terza su 4)

-XX:+AggressiveHeap (RAM 256+Mb) ottimizza per applicazioni
“memory-allocation intensive”… è pensato per sistemi con molta
memoria e molti processori, ma – per jre 1.4.1+ – funziona bene anche
con “solo” 4 cpu

-XX:+UseAdaptiveSizePolicy regola automaticamente l’utilizzo di una
parte dell’heap (young/tenured ratio)

-Xincgc per abilitare l’utilizzo del GC “incremental”

-XX:+UseConcMarkSweepGC (jre 1.4.1+) uso della GC concorrente per
“old”, può essere usato contemporaneamente alla policy (a) per gli
young
-XX:CMSInitiatingOccupancyFraction=n indica la frazione di heap
occupato prima che avvenga la gc… impostarlo all’80-90% può
garantire interruzioni meno frequenti. Attenzione! Siccome il GC in 4
fasi non disabilita i setter metre libera la memoria, impostarla ad un
valore troppo elevato può causare problemi di OutOfMemory quando con
l’utilizzo della policy (a) non se ne avrebbero avuti

-XX:SurvivorRatio=z quanta parte del “survivor space heap” deve essere
usata prima che gli oggetti vengano promossi ad “old”. il default è
50%

-XX;MaxTenuringThreshold=y quanto gli oggetti debbano “invecchiare”,
ovvero quante volte debbano essere copiati, prima di diventare “old”

in ambito web, dove molti oggetti sono usati una o poche volte prima
di essere dereferenziati, è possibile settare y a zero per forzare
l’intervento della policy b e quindi causare interruzioni + brevi. è
conveniente associare questo parametro ad un valore molto alto di
-XX:SurvivorRatio in modo che si passi direttamente da “eden” a “old”

-XX:+AggressiveOpts utilizza ottimizzazioni che saranno probabilmente
attive di default nella prossima release della jvm… attenzione: le
prestazioni possono variare da versione a versione… da una relese
all’altra potrebbero cambiare le opzioni e non è garantito che le
ottimizzazioni che attualmente hanno luogo se si attiva quest’opzione,
effettivamente poi saranno di default.

un esempio pratico evidenzia che in un’applicazione SIP migliori le
performances semplicemente cambiando i parametri che regolano il
funzionamento del GC

caso 1:
java -Xmx512m -Xms512m -XX:MaxNewSize=24m -XX:NewSize=24m -XX:SurvivorRatio=2

“old” latency 3s (!!!!)
“young” latency 110ms
GC sequential overhead 18.9%

caso 2:
java -Xmx512m -Xms512m -XX:MaxNewSize=24m -XX:NewSize=24m
-XX:SurvivorRatio=128 -XX:+UseConcMarkSweepGC
-XX:MaSInitiatingOccupancyfraction=60

“old” latency 115ms
“young” latency 100ms
GC sequential overhead 8.6%

caso 3:
java -Xmx512m -Xms512m -XX:MaxNewSize=24m -XX:NewSize=24m
-XX:SurvivorRatio=2 -XX:UseParNewGC +UseConcMarkSweepGC
-XX:MaSInitiatingOccupancyfraction=60

“old” latency 145ms
“young” latency 50ms
GC sequential overhead 5.9%

passare da 18.9% a 5.9% non mi pare male
e nemmeno dai 3 secondi di interruzione per una GC a 145ms…

non dimetichiamoci che, oltre alle opzioni relative al garbage
collector, per applicazioni enterprise è necessario
– aumentare la dimensione massima dell’heap (quella di default è
veramente bassa)
– settare -Xms e -Xmx allo stesso valore in modo da avere un
comportamento più costante nel tempo

per determinare in che modo dimensionare le varie parti dell’heap si
può procedere nel seguente modo
– di fa una raffigurazione del ciclo di vita degli oggetti sul piano
cartesiano e si stima la quantità di “young” e “old”… è bene
comunque fare diverse prove
– se ci sono molte pause dovute alla gc, conviene assegnare via via
più memoria per “young”
– va tenuto conto che quando ci si avvicina a metà della dimensione
dell’heap assegnato a “young”, le prestazioni peggiorano

riferimenti
http://java.sun.com/docs/hotspot/gc1.4.2/
http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html (più
aggiornato ma non contiene la spiegazione di tutti i dettagli)

http://java.sun.com/developer/technicalArticles/Programming/turbo/

http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp (elenco
di varie opzioni per la vm)

Annunci

~ di mspike su luglio 23, 2008.

Una Risposta to “GC Tweaks”

  1. Quality articles is the secret to invite the viewers to pay a visit the web site,
    that’s what this web page is providing.

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

 
%d blogger hanno fatto clic su Mi Piace per questo: