2011-04-19 15 views
9

sto correndo un server Java che utilizza CMS per il collettore di ruolo. Correndo sotto un test di carico, vedo collezioni giovani ogni 1 s e tenure (concomitanti) circa ogni 5 m. Questo è buono.Java CMS essere ignorato e ottenere completa GC Invece

Quando eseguo con traffico reale di circa 1/2 della capacità, ottengo giovani raccolte circa ogni 4s e di ruolo (! Parallelo, fermare il mondo!) Circa ogni 7m. Perché la JVM decide di eseguire raccolte complete per il mondo intero invece di utilizzare il raccoglitore CMS?

Dal gc.log si può vedere il "GC completa" in esecuzione e presa in consegna 3s da completare. Non c'è nessun errore di modalità simultanea qui. Niente richiede esplicitamente una collezione.

1350.596: [GC 1350.596: [ParNew 
Desired survivor size 119275520 bytes, new threshold 3 (max 3) 
- age 1: 34779376 bytes, 34779376 total 
- age 2: 17072392 bytes, 51851768 total 
- age 3: 24120992 bytes, 75972760 total 
: 1765625K->116452K(1864192K), 0.1560370 secs] 3887120K->2277489K(5009920K), 0.1561920 secs] [Times: user=0.40 sys=0.04, real=0.16 secs] 
1355.106: [GC 1355.107: [ParNew 
Desired survivor size 119275520 bytes, new threshold 3 (max 3) 
- age 1: 44862680 bytes, 44862680 total 
- age 2: 20363280 bytes, 65225960 total 
- age 3: 16908840 bytes, 82134800 total 
: 1747684K->123571K(1864192K), 0.1068880 secs] 3908721K->2307790K(5009920K), 0.1070130 secs] [Times: user=0.29 sys=0.04, real=0.11 secs] 
1356.106: [Full GC 1356.106: [CMS: 2184218K->1268401K(3145728K), 3.0678070 secs] 2682861K->1268401K(5009920K), [CMS Perm : 145090K->145060K(262144K)], 3.0679600 secs] [Times: user=3.05 sys=0.02, real=3.07 secs] 
1361.375: [GC 1361.375: [ParNew 
Desired survivor size 119275520 bytes, new threshold 3 (max 3) 
- age 1: 33708472 bytes, 33708472 total 
: 1631232K->84465K(1864192K), 0.0189890 secs] 2899633K->1352866K(5009920K), 0.0191530 secs] [Times: user=0.19 sys=0.00, real=0.02 secs] 
1365.587: [GC 1365.587: [ParNew 
Desired survivor size 119275520 bytes, new threshold 3 (max 3) 
- age 1: 33475320 bytes, 33475320 total 
- age 2: 22698536 bytes, 56173856 total 
: 1715697K->67421K(1864192K), 0.0229540 secs] 2984098K->1335822K(5009920K), 0.0231240 secs] [Times: user=0.25 sys=0.00, real=0.03 secs] 

Qui ci sono le bandiere JVM:

-server -Xss256K -Xms5120M -Xmx5120M -XX:NewSize=2048M -XX:MaxNewSize=2048M 
-XX:SurvivorRatio=7 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC 
-XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=80 
-XX:+UseCMSInitiatingOccupancyOnly -XX:CMSFullGCsBeforeCompaction=1 
-XX:SoftRefLRUPolicyMSPerMB=73 -verbose:gc -XX:+PrintGCDetails 
-XX:+PrintGCTimeStamps -XX:+PrintTenuringDistribution -Xloggc:logs/gc.log 
-XX:MaxPermSize=256m -XX:PermSize=256m -XX:MaxTenuringThreshold=3 
+0

qualcosa di interessante ... Dopo circa 2800 secondi (+/- 200S) CMS comincia ad essere usato di nuovo. In genere, 1 o 2 tentativi vengono interrotti con "modalità concomitante interrotta" e, successivamente, tutto ha esito positivo. Il traffico è rimasto invariato durante questo periodo. 2415,457 - GC completa ... giovani collezioni ... 2684,320 - CMS-iniziale-mark (prima CMS-mark in qualsiasi parte del registro) 2684,436 - Full GC (modalità simultanea interrotto) ... giovane .. . ... altro CMS interrotto ... ... giovane ... 3224,451 - CMS-iniziale-mark 3234,855 - giovane 3230,254 - CMS-osservazione 3231,972 - CMS-reset (fatto) ... tutto bene ... –

+0

Secondo il [codice CMS] (http://cr.openjdk.java.net/~jrose/6863023/diff-04-to-05/raw_files/new/src/share/vm/gc_implementation /concurrentMarkSweep/concurrentMarkSweepGeneration.cpp), il messaggio "concurrent mode interrupted" e si verifica a causa di (a) 'GCCause :: is_user_requested_gc' o (b)' GCCause :: is_serviceability_requested_gc'. Ciò significa che la causa è (a) '_java_lang_system_gc' o' _jvmti_force_gc', o (b) '_jvmti_force_gc',' _heap_inspection', o '_heap_dump'.Sembra che la stessa cosa potrebbe essere la fonte sia del GC completo che delle interruzioni, ma nessuno di questi dovrebbe accadere. –

+0

Ecco i primi 8000 secondi del [file registro GC] (http://www.backgroundexposure.com/gc.log.txt) da un server se sei interessato. –

risposta

2

Se lo spazio reversibilità non è abbastanza grande, può innescare un GC completa. (Sembra che si stia lamentando del rapporto di sopravvissuti)

O è necessario ridurre il rapporto di sopravvivenza o una soluzione migliore è probabile che aumenti il ​​tuo NewSize in modo che meno oggetti sopravvivano dallo spazio eden. Ho uno spazio eden di 6 GB;)

+0

Lo spazio del superstite si manterrà generalmente intorno ai 4-6 cicli ma, poiché non diminuisce la quantità in ogni ciclo, lo limito a 3 cicli al fine di ridurre la quantità di meme non necessaria. –

+0

BTW, la mia dimensione di Eden viene scelta per causare raccolte non più frequenti di ogni 1s a pieno carico e con un tempo medio di stop-the-world di 50ms. Le richieste di solito ricevono una risposta inferiore a 50 ms con il 99,9% in meno di 250 ms. –

+0

BTW: creando un minimo di oggetti, lo spazio Eden è sufficiente per un'intera giornata. Ho un GC completo ogni notte alle 5 del mattino, nessun GC secondario. ;) Il tempo di risposta è inferiore a 0,1 ms un'alta percentuale del tempo. –

1

Mi sembra di ricordare di vedere un fenomeno simile l'anno scorso durante l'ottimizzazione di un mucchio di grandi dimensioni per evitare piena GC. Penso che potresti voler ridurre la dimensione di eden. Questo è abbastanza grande rispetto alla generazione di tenured.

Quello che credo potrebbe accadere è che più del tuo eden diventa "vecchio" contemporaneamente con il tuo traffico a velocità 1/2 rispetto a quello a piena velocità (dove non stanno sopravvivendo). Il che significa che più di esso ha bisogno di trasferirsi a tempo indeterminato in una sola volta. E se non si adatta in quel momento potrebbe attivare un GC completo per fare spazio.

Per avere un riferimento qui è quello che usiamo ora 6GB di cumuli 24GB:

-XX:NewRatio=4 -XX:SurvivorRatio=8 -XX:+UseCompressedOops 
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+DisableExplicitGC 
-XX:+UseCMSInitiatingOccupancyOnly -XX:+CMSClassUnloadingEnabled 
-XX:+CMSScavengeBeforeRemark -XX:CMSInitiatingOccupancyFraction=68 
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:logs/gc.log 

E 'abbastanza simile alla tua già. La cosa bella dell'utilizzo di tutti i rapporti è che si può facilmente cambiare la dimensione dell'heap e (generalmente) le scale in modo appropriato. Un'altra nota è che -XX:+UseCompressedOops genere può utilizzare il 40% meno memoria riducendo indirizzamento a 64 bit a 32 bit (funziona solo fino a 32GB).

+0

Un GC completo attivato a causa di una mancata promozione degli oggetti Young in Tenured appare nel log come un "errore in modalità simultanea" che non è presente. Ne ho visti molti in passato; l'occupazione = 80 è il risultato di un'accurata messa a punto. Le mie richieste hanno quasi sempre una risposta in <250ms e così la maggior parte dell'Eden viene buttata fuori immediatamente, con meno del 10% che viene copiata sul sopravvissuto. Circa 1/4 a 1/2 di questo viene espulso nel ciclo successivo, dopo di che non si riduce molto, non importa quante più copie sono consentite (da qui il TenuringThreshold = 3). Meno del 5% dello spazio di Eden viene messo in possesso. –

+0

A quanto pare ho parlato troppo presto. Abbassare la mia "percentuale di occupazione" a 60 ha effettivamente fermato questo. Forse non è considerato un "errore in modalità simultanea" a meno che la JVM non abbia tentato almeno una raccolta CMS dall'avvio (anche se non l'ha capito, non capisco). Persino i contatori interni alla JVM non lo contano come tali, i messaggi di registro o no. Ora ... Perché spostare 15-30 MB in un nuovo spazio Tenured di 3G ha un problema con un'occupazione di 70 ma funziona con 65? 30 MB sono solo l'1% del 3G. –