2010-05-19 17 views
9

Di tanto in tanto, da qualche parte tra una volta ogni 2 giorni a una volta ogni 2 settimane, la mia domanda si blocca in una posizione apparentemente casuale nel codice con: java.lang.OutOfMemoryError: GC overhead limit exceeded. Se I google questo errore vengo a this SO question e che mi portano a this piece of sun documentation che expains:Durata eccessiva GC Tempo in "java.lang.OutOfMemoryError: limite di testa GC superato"

The parallel collector will throw an OutOfMemoryError if too much time is being spent in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, an OutOfMemoryError will be thrown. This feature is designed to prevent applications from running for an extended period of time while making little or no progress because the heap is too small. If necessary, this feature can be disabled by adding the option -XX:-UseGCOverheadLimit to the command line.

Il che mi che la mia domanda è apparentemente spendendo il 98% del tempo totale di garbage collection dice di recuperare solo il 2% del mucchio.

Ma il 98% di che ora? Il 98% delle intere due settimane in cui è stata eseguita l'applicazione? Il 98% dell'ultimo millisecondo?

Sto cercando di determinare un approccio migliore per risolvere questo problema piuttosto che utilizzare semplicemente -XX:-UseGCOverheadLimit ma sento la necessità di comprendere meglio il problema che sto risolvendo.

+3

Dalla documentazione, sembra essere il 98% delle 2 settimane intere. Hai abilitato i registri GC con questi flag -verbose: gc -XX: + PrintGCDetails XX: + PrintGCTimeStamps -Xloggc: PATH_FROM_ROOT/gclog.log. Sarebbe bello vedere l'ora di esecuzione dell'app e il tempo di arresto dovuti a GC. – JoseK

+0

La registrazione GC è un bel suggerimento, ci proverò. Il 98% delle 2 settimane sembra improbabile, ma hai ragione, questo è ciò che implicano i documenti. Spero che sia solo la scrittura imprecisa –

+0

Hai scoperto il significato del 98% del tempo? La mia opinione è che GC dovrebbe occuparsi del 98% dell'utilizzo delle applicazioni nel momento stesso in cui si verifica l'eccezione e non per le 2 settimane. –

risposta

6

I'm trying to determine a best approach to actually solving this issue rather than just using -XX:-UseGCOverheadLimit but I feel a need to better understand the issue I'm solving.

Bene, si sta utilizzando troppa memoria e, dal suono, è probabilmente a causa di una perdita di memoria lenta.

Puoi provare ad aumentare la dimensione dell'heap con -Xmx, il che sarebbe di aiuto se non si tratta di una perdita di memoria ma un segno che la tua app ha effettivamente bisogno di molto heap e l'impostazione che hai attualmente è leggermente bassa. Se si tratta di una perdita di memoria, questo semplicemente rimandare l'inevitabile.

Per verificare se si tratta di una perdita di memoria, indicare alla VM di eseguire il dump di heap su OOM utilizzando lo switch -XX:+HeapDumpOnOutOfMemoryError e quindi analizzare il dump dell'heap per vedere se ci sono più oggetti di qualche tipo di quelli che dovrebbero esserci. http://blogs.oracle.com/alanb/entry/heap_dumps_are_back_with è un buon punto di partenza.


Edit: Il destino ha voluto che mi è capitato di correre in questo problema io stesso appena un giorno dopo questa domanda è stato chiesto, in un'applicazione batch stile. Ciò non è stato causato da una perdita di memoria e anche l'aumento delle dimensioni dell'heap non è stato di aiuto. Quello che ho fatto è stato in realtà a diminuire le dimensioni dell'heap (da 1 GB a 256 MB) per rendere i GC completi più veloci (anche se un po 'più frequenti). YMMV, ma vale la pena sparare.

Edit 2: Non tutti i problemi risolti dal più piccolo mucchio ... passo successivo stava permettendo l'G1 garbage collector che sembra fare un lavoro migliore di CMS.

+0

Sto provando un po 'di profilazione, e proverò anche quello. Grazie. –

+0

Ho seguito un percorso simile a quello che hai fatto, sperimentando i parametri. Alla fine, l'aumento della dimensione dell'heap e qualche ritocco del mio codice (non ho trovato perdite di memoria) sembra aver risolto il mio problema. –

+0

perché dovresti usare CMS o G1 in un'app in stile batch? Il collettore della produttività non è migliore? – endless

1

Il> 98% verrebbe misurato nello stesso periodo in cui viene recuperato meno del 2% di memoria.

È possibile che non ci sia un periodo fisso per questo. Ad esempio, se il controllo di OOM dovesse essere eseguito dopo ogni 1.000.000 di controlli in tempo reale dell'oggetto. Il tempo necessario dipende dalla macchina.

Probabilmente non è possibile "risolvere" il problema aggiungendo -XX:-UseGCOverheadLimit. Il risultato più probabile è che la tua applicazione rallenti a passo d'uomo, usi un po 'più di memoria, e poi colpisca il punto in cui il GC semplicemente non recupera più memoria. Invece, correggi le perdite di memoria e poi (se ancora necessario) aumenta le dimensioni dell'heap.

1

But 98% of what time? 98% of the entire two weeks the application has been running? 98% of the last millisecond?

La risposta semplice è che non è specificato. Tuttavia, in pratica l'euristico "funziona", quindi non può essere né l'una né l'altra delle due interpretazioni estreme che lei ha postulato.

Se si in realtà si desidera sapere quale intervallo di tempo viene eseguito sulle misurazioni, è sempre possibile leggere il codice sorgente di OpenJDK 6 o 7. Ma non mi preoccuperei perché non ti aiuterà a risolvere il tuo problema.

L'approccio "migliore" è quello di fare qualche lettura sulla messa a punto (a partire dalle pagine di Oracle/Sun), e poi accuratamente "Twiddle le manopole di regolazione". Non è molto scientifico, ma lo spazio problema (con precisione predicendo applicazione + prestazioni GC) è "troppo difficile" dato gli strumenti che sono attualmente disponibili.

Problemi correlati