Garbage collection Java G1 in produzione


91

Dato che Java 7 utilizzerà la nuova garbage collection G1 per impostazione predefinita, Java sarà in grado di gestire un mucchio di un ordine di grandezza più grande senza presunti tempi di pausa GC "devastanti"? Qualcuno ha effettivamente implementato G1 in produzione, quali sono state le tue esperienze?

Per essere onesti, l'unica volta che ho visto pause GC davvero lunghe è su cumuli molto grandi, molto più di quanto avrebbe una workstation. Per chiarire la mia domanda; G1 aprirà la porta a cumuli di centinaia di GB? TB?


15
Anche se potrebbe essere riformulato in modo più specifico, questa non è una domanda orribile. Vorrei davvero che le persone si dovessero spiegare meglio di "Non una domanda" quando si vota per chiudere.
Bill K

Non ho votato per chiudere, ma avrei voluto che l'OP avesse svolto un lavoro più obiettivo nel dettagliare le sue lamentele con l'attuale GC. Inoltre, "Java" è un linguaggio mentre sta parlando di un'implementazione, e non so cosa significhi "implementare G1 in produzione", specialmente con il futuro del resto della domanda. Se sarà in Java 7, sicuramente nessuno lo ha usato in produzione?
Pascal Cuoq

6
@Pascal G1 è stata una funzionalità sperimentale disponibile nel JDK dall'aggiornamento 14 di JDK 6. Con "implementare G1 in produzione" penso che intendesse effettivamente usarlo, non è così difficile da capire. E mentre sono d'accordo che G1 fa parte di JDK 7, non Java, una ricerca di Java 7 su Google restituisce la home page di JDK 7 come primo risultato ed entrambi i termini sono spesso usati in modo intercambiabile. @ Benju Non mi fiderei dei risultati ottenuti con G1 sull'attuale JDK in quanto è sperimentale, molte cose potrebbero cambiare da ora alla versione ufficiale.
teto

2
Sembra che JDK 7, inclusi gli aggiornamenti 1,2 e 3, non utilizzi G1 gc per impostazione predefinita. Puoi verificarlo tramite jinfo -flag UseG1GC pid
George

Risposte:


34

Sembra che il punto di G1 sia quello di avere tempi di pausa più piccoli, anche al punto in cui ha la capacità di specificare un obiettivo di tempo di pausa massimo.

La raccolta dei rifiuti non è più solo un semplice affare "Ehi, è pieno, spostiamo tutto in una volta e ricominciamo": è un sistema a thread in background straordinariamente complesso, multilivello. Può eseguire gran parte della sua manutenzione in background senza pause e utilizza anche la conoscenza dei modelli attesi del sistema in fase di esecuzione per aiutare, come presumere che la maggior parte degli oggetti muoia subito dopo la creazione, ecc.

Direi che i tempi di pausa di GC continueranno a migliorare, non a peggiorare, con le versioni future.

MODIFICARE:

rileggendo mi è venuto in mente che utilizzo Java quotidianamente - Eclipse, Azureus e le app che sviluppo, ed è passato MOLTO TEMPO da quando ho visto una pausa. Non una pausa significativa, ma intendo affatto una pausa.

Ho visto delle pause quando faccio clic con il pulsante destro del mouse su Windows Explorer o (occasionalmente) quando collego un determinato hardware USB, ma con Java --- nessuno.

GC è ancora un problema con qualcuno?


D'accordo: l'unica volta che ho visto le pause GC è quando le ho provocate deliberatamente o accidentalmente con un codice di creazione di immondizia massicciamente parallelo .....
mikera

28
Sì, GC è ancora un problema quando inizi a gestire grossi cumuli (> 16 GB), specialmente con generazioni di ruolo di grandi dimensioni.
The Alchemist

2
@ the-alchemist Eeeek !!!, ho visto di sfuggita il tuo commento un paio di volte e mi ha colpito che hai detto 16 GB !! Anche se sono assolutamente sicuro che tu abbia ragione sul fatto che questo può causare enormi ritardi, voglio controllare che tu abbia disabilitato TUTTI gli scambi. Su un sistema di memoria di grandi dimensioni, qualsiasi scambio di java ucciderà assolutamente il tuo sistema (poiché GC è molto ostile allo swap). Sono sicuro che l'hai già fatto, ma volevo solo menzionarlo, perché farebbe un'enorme differenza. Non ho mai visto un PC con così tanta ram: quanta ne hai? 32g?
Bill K

8
Sì, i GC sono problematici per i servizi in quanto sono ciò che rende MOLTO difficile migliorare i limiti TP99.9 (e superiori). In particolare, i GC di "vecchia generazione" possono essere trappole mortali che bloccano la JVM (e il servizio) per diversi secondi; e per i servizi che tipicamente servono richieste in milli secondi a una cifra (o bassa a due cifre) questo è problematico. Per quello che vale, questo è stato un problema pratico con lo storage back-end utilizzato dal servizio Simple Queue di Amazon (non è possibile entrare in molti dettagli poiché è interno ad AWS).
StaxMan

21
La cosa fastidiosa di GC è che Azul ha inventato anni fa un ingegnoso algoritmo GC (Azul C4) che può facilmente far fronte a centinaia di gigabyte senza tempi di pausa apprezzabili, facendo un uso molto intelligente dell'hardware di memoria del processore. Ma nessuno lo sa e non sarà implementato presto nelle principali versioni di Java poiché necessita di supporto da parte del sistema operativo. E i fornitori di sistemi operativi non faranno nulla finché le persone non conosceranno l'algoritmo e non eserciteranno pressioni sui fornitori del sistema operativo. Vedi azulsystems.com/zing/pgc , managedruntime.org
Hans-Peter Störr

58

L'ho testato con un'applicazione pesante: 60-70 GB allocati nell'heap, con 20-50 GB in uso in qualsiasi momento. Con questo tipo di applicazioni, è un eufemismo dire che il tuo chilometraggio può variare. Sto eseguendo JDK 1.6_22 su Linux. Le versioni minori sono importanti: prima della 1.6_20, c'erano bug in G1 che causavano NullPointerExceptions casuali.

Ho scoperto che è molto bravo a mantenere l'obiettivo della pausa che gli dai la maggior parte del tempo. L'impostazione predefinita sembra essere una pausa di 100 ms (0,1 secondi) e gli ho detto di fare la metà (-XX: MaxGCPauseMillis = 50). Tuttavia, una volta che la memoria è davvero scarsa, va nel panico e fa una raccolta dei rifiuti completa. Con 65 GB, ciò richiede tra 30 secondi e 2 minuti. (Il numero di CPU probabilmente non fa la differenza; probabilmente è limitato dalla velocità del bus.)

Rispetto a CMS (che non è il GC del server predefinito, ma dovrebbe essere per i server Web e altre applicazioni in tempo reale), le pause tipiche sono molto più prevedibili e possono essere rese molto più brevi. Finora ho avuto più fortuna con CMS per le enormi pause, ma potrebbe essere casuale; Li vedo solo poche volte ogni 24 ore. Al momento non sono sicuro quale sarà più appropriato nel mio ambiente di produzione, ma probabilmente G1. Se Oracle continua a ottimizzarlo, sospetto che G1 alla fine sarà il chiaro vincitore.

Se non hai problemi con i garbage collector esistenti, non c'è motivo di considerare G1 in questo momento. Se stai eseguendo un'applicazione a bassa latenza, come un'applicazione GUI, G1 è probabilmente la scelta giusta, con MaxGCPauseMillis impostato su un valore molto basso. Se stai eseguendo un'applicazione in modalità batch, G1 non ti compra nulla.


14

Sebbene non abbia testato G1 in produzione, ho pensato di commentare che i GC sono già problematici per i casi senza cumuli "giganteschi". In particolare, i servizi con solo, diciamo, 2 o 4 gig possono essere gravemente influenzati da GC. I GC di giovane generazione di solito non sono problematici poiché terminano in millisecondi a una cifra (o al massimo a due cifre). Ma le raccolte di vecchia generazione sono molto più problematiche in quanto richiedono più secondi con dimensioni di vecchia generazione di 1 gig o superiore.

Ora: in teoria CMS può aiutare molto lì, poiché può eseguire la maggior parte delle sue operazioni contemporaneamente. Tuttavia, nel tempo ci saranno casi in cui non può farlo e deve ripiegare per "fermare il mondo". E quando ciò accade (dopo, diciamo, 1 ora - non spesso, ma ancora troppo spesso), beh, tieniti stretto i tuoi fottuti cappelli. Potrebbe volerci un minuto o più. Ciò è particolarmente problematico per i servizi che tentano di limitare la latenza massima; invece di impiegare, diciamo, 25 millisecondi per servire una richiesta, ora ci vogliono dieci secondi o più. Per aggiungere danni agli insulti, i clienti spesso scadono la richiesta e riprovano, portando a ulteriori problemi (noti anche come "tempesta di merda").

Questa è un'area in cui si sperava che G1 potesse aiutare molto. Ho lavorato per una grande azienda che offre servizi cloud per l'archiviazione e l'invio di messaggi; e non abbiamo potuto usare CMS poiché, sebbene la maggior parte delle volte funzionasse meglio delle varietà parallele, presentava questi crolli. Quindi per circa un'ora le cose andarono bene; e poi le cose hanno colpito la ventola ... e poiché il servizio era basato su cluster, quando un nodo ha avuto problemi, altri ne hanno seguiti tipicamente (poiché i timeout indotti da GC fanno sì che altri nodi credano che il nodo si sia arrestato in modo anomalo, portando a reindirizzamenti).

Non credo che GC sia un grosso problema per le app e forse anche i servizi non in cluster sono meno spesso interessati. Ma sempre più sistemi sono raggruppati in cluster (specialmente grazie agli archivi dati NoSQL) e le dimensioni degli heap stanno crescendo. I GC OldGen sono super-linearmente correlati alla dimensione dell'heap (il che significa che raddoppiare la dimensione dell'heap più che raddoppia il tempo GC, supponendo che anche la dimensione del set di dati live raddoppi).


13

Il CTO di Azul, Gil Tene, ha una bella panoramica dei problemi associati alla Garbage Collection e una revisione di varie soluzioni nella sua presentazione Understanding Java Garbage Collection e Cosa puoi fare al riguardo , e ci sono ulteriori dettagli in questo articolo: http: // www.infoq.com/articles/azul_gc_in_detail .

Il Garbage Collector C4 di Azul nella nostra JVM Zing è sia parallelo che concorrente e utilizza lo stesso meccanismo GC sia per la nuova che per la vecchia generazione, lavorando contemporaneamente e compattandosi in entrambi i casi. Soprattutto, C4 non ha ripiegamento sul blocco del mondo. Tutta la compattazione viene eseguita contemporaneamente all'applicazione in esecuzione. Abbiamo clienti che eseguono operazioni molto grandi (centinaia di GByte) con tempi di pausa GC nel caso peggiore di <10 msec e, a seconda dell'applicazione, spesso tempi inferiori a 1-2 msec.

Il problema con CMS e G1 è che a un certo punto la memoria heap Java deve essere compattata ed entrambi i garbage collector stop-the-world / STW (cioè sospendono l'applicazione) per eseguire la compattazione. Quindi, sebbene CMS e G1 possano eliminare le pause STW, non le eliminano. Il C4 di Azul, tuttavia, elimina completamente le pause STW ed è per questo che Zing ha pause GC così basse anche per dimensioni di heap gigantesche.

E per correggere un'affermazione fatta in una risposta precedente, Zing non richiede alcuna modifica al sistema operativo. Funziona proprio come qualsiasi altra JVM su distribuzioni Linux non modificate.


3
Mi chiedo solo come C4 di Azul abbia ottenuto ciò che hai detto e perché Sun o Oracle non possono. C'è qualche grande segreto o questo è solo un compromesso?
George

5
Il C4 di Azul ha una tecnologia davvero unica che ha le sue origini nelle appliance di elaborazione hardware di Azul (che utilizza processori specializzati costruiti per eseguire app Java aziendali) ed è stato evoluto per funzionare su server x86 regolari che eseguono Linux. Ogni altro garbage collector di classe enterprise (sia Oracle che IBM) a un certo punto deve fare pause stop-the-world: l'attributo unico di C4 di Azul è che non fa mai queste pause STW problematiche. Se sei curioso, gli inventori del collezionista C4 hanno pubblicato un documento su come funziona: dl.acm.org/citation.cfm?id=1064988 .
Scott Sellers

Scott, ho letto qui blog.mikemccandless.com/2012/07/… che Azul spedisce un modulo del kernel che pre-alloca la memoria per l'utilizzo JVM. Non è vero? Se vero, non si tratta di una modifica del kernel, ma comunque di una modifica.
Dan Pritts

4
George, due parole: brevetto protetto. Dan, quando acquisti Zing, parte di ciò per cui stai pagando è che le persone dell'assistenza lo ottimizzino per la tua applicazione, e questo include l'allocazione dell'utilizzo complessivo della memoria di sistema. Il modulo del kernel stesso impedisce la scrittura su un blocco di memoria che viene raccolto in modo garbage. Questa è la salsa segreta che lo rende "senza pausa": i thread si mettono in pausa solo se provano a scrivere su uno di quei blocchi, e poi solo il tempo necessario per compattare quel blocco.
David Leppik

13

Stiamo già utilizzando G1GC, da quasi due anni. Sta andando alla grande nel nostro sistema di elaborazione delle transazioni mission-critical e si è dimostrato un ottimo supporto rispetto a throughput elevato, pause ridotte, concorrenza e gestione ottimizzata della memoria pesante.

Stiamo utilizzando le seguenti impostazioni JVM:

-server -Xms512m -Xmx3076m -XX:NewRatio=50 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -XX:+AggressiveOpts -XX:+UnlockExperimentalVMOptions -XX:MaxGCPauseMillis=400 -XX:GCPauseIntervalMillis=8000 -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime

Aggiornato

-d64 -server -Xss4m -Xms1024m -Xmx4096m -XX:NewRatio=50 -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:-DisableExplicitGC -XX:+AggressiveOpts -Xnoclassgc -XX:+UseNUMA -XX:+UseFastAccessorMethods -XX:ReservedCodeCacheSize=48m -XX:+UseStringCache -XX:+UseStringDeduplication -XX:MaxGCPauseMillis=400 -XX:GCPauseIntervalMillis=8000

5
In Java 8, non è necessario impostare -XX: + UseCompressedOops o -XX: + DoEscapeAnalysis, booth è attivo come impostazione predefinita. Vedi: docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
Mirko Ebert

8

Il raccoglitore G1 riduce l'impatto delle collezioni complete. Se hai un'applicazione in cui hai già ridotto la necessità di raccolte complete, il raccoglitore Sweep di mappe simultanee è altrettanto buono e secondo la mia esperienza ha tempi di raccolta minori più brevi.


"nota che l'uso di produzione di G1 è consentito solo se è stato acquistato un contratto di supporto Java.", groups.google.com/forum/#!topic/javaposse/Vm0a4H-QY54 , quindi è un mito o no?
Christophe Roussy

1
@ChristopheRoussy Non so più se questo è vero (o in effetti ho la prova che è mai stato vero) Non richiede -XX: + UnlockCommercialFeatures quindi sospetto che G1 non richieda una licenza.
Peter Lawrey


5

Recentemente sono stato spostato da

Da CMS a G1GC con heap 4G e processore a 8 core su server con JDK 1.7.45 .

(JDK 1.8.x G1GC è preferito rispetto a 1.7 ma a causa di alcune limitazioni, devo attenermi alla versione 1.7.45)

Ho configurato i seguenti parametri chiave e mantenuto tutti gli altri parametri ai valori predefiniti.

-XX:G1HeapRegionSize=n, XX:MaxGCPauseMillis=m, -XX:ParallelGCThreads=n, 
-XX:ConcGCThreads=n apart from -Xms and -Xmx

Se vuoi mettere a punto questi parametri, dai un'occhiata a questo articolo di Oracle .

Osservazioni chiave:

  1. L'utilizzo della memoria è coerente con G1GC a differenza di alti e bassi con CMS
  2. Il tempo massimo di pausa GC è inferiore rispetto a CMS
  3. Il tempo speso nella raccolta dei rifiuti è leggermente elevato in G1GC rispetto a CMS.
  4. Il numero di raccolte principali è quasi trascurabile rispetto al CMS
  5. Il numero di raccolte minori è di fascia più alta rispetto a CMS

Tuttavia, sono ancora felice che il tempo di pausa di Max GC sia inferiore a quello di CMS. Ho impostato il tempo massimo di pausa GC a 1,5 secondi e questo valore non è stato ancora superato.

Domanda SE correlata:

Garbage collection e documentazione Java 7 (JDK 7) su G1


4

CMS può portare a prestazioni ridotte lentamente anche se lo si esegue senza accumulare oggetti in possesso. Ciò è dovuto alla frammentazione della memoria che G1 presumibilmente evita.

Il mito su G1 disponibile solo con supporto a pagamento è proprio questo, un mito. Sun e ora Oracle hanno chiarito questo nella pagina JDK.


4

G1 GC dovrebbe funzionare meglio. Ma se si imposta -XX: MaxGCPauseMill è troppo aggressivo, i rifiuti verranno raccolti troppo lentamente. Ed è per questo che il GC completo si è attivato nell'esempio di David Leppik.


4

Ho appena implementato G1 Garbage Collector nel nostro progetto Terracotta Big Memory. Lavorando su diversi tipi di collettori, G1 ci ha dato i migliori risultati con un tempo di risposta inferiore a 600 ms.

Puoi trovare i risultati del test (26 in totale) qui

Spero che sia d'aiuto.


3

Di recente ho migrato parte di Twicsy su un nuovo server con 128 GB di RAM e ho deciso di utilizzare 1.7. Ho iniziato a utilizzare tutte le stesse impostazioni di memoria che ho usato con 1.6 (ho diverse istanze in esecuzione facendo varie cose, ovunque da 500 MB di heap fino a 15 GB, e ora una nuova con 40 GB) e non ha funzionato affatto bene . 1.7 sembra utilizzare più heap di 1.6 e ho riscontrato molti problemi nei primi giorni. Fortunatamente avevo molta RAM con cui lavorare e ho aumentato la RAM per la maggior parte dei miei processi, ma avevo ancora alcuni problemi. Il mio normale MO prevedeva di utilizzare una dimensione heap minima molto piccola di 16 m, anche con un heap massimo di diversi gigabyte, quindi attivare GC incrementale. Ciò ha mantenuto le pause al minimo. Tuttavia, ora non funziona e ho dovuto aumentare la dimensione minima a quello che mi aspettavo di usare in media nell'heap, e questo ha funzionato molto bene. Ho ancora attivato il GC incrementale, ma lo proverò senza. Nessuna pausa di sorta adesso, e le cose sembrano andare molto velocemente. Quindi, penso che la morale della storia sia non aspettarti che le impostazioni della tua memoria si traducano perfettamente da 1.6 a 1.7.


2

G1 rende l'applicazione molto più agile: la latenza dell'applicazione aumenterà - l'app può essere denominata "soft-real-time". Questo viene fatto sostituendo due tipi di cicli GC (piccoli minori e uno grande su Tenured Gen) con quelli piccoli di uguale dimensione.

Per maggiori dettagli guarda questo: http://geekroom.de/java/java-expertise-g1-fur-java-7/


1

Sto lavorando con Java, per Heap piccoli e grandi, e la questione del GC e Full GC appare ogni giorno, poiché i vincoli potrebbero essere più rigidi di altri: in determinati ambienti, 0,1 secondi di scavenger GC o Full GC, kill semplicemente la funzionalità e avere una configurazione a grana fine e capacità è importante (CMS, iCMS, altri ... l'obiettivo è qui per avere il miglior tempo di risposta possibile con il trattamento quasi in tempo reale (qui il trattamento in tempo reale è spesso di 25 ms) , quindi, in pratica, qualsiasi miglioramento dell'ergonomia e dell'euristica di GC è il benvenuto!


1

Uso G1GC su Java 8 e anche con Groovy (anche Java 8) e sto eseguendo vari tipi di carichi di lavoro e in generale G1GC funziona in questo modo:

  • L'utilizzo della memoria è molto basso, ad esempio 100 MB invece di 500 MB rispetto alle impostazioni Java predefinite

  • Il tempo di risposta è costante e molto basso

  • Le prestazioni tra le impostazioni predefinite e G1GC sono il 20% di rallentamento quando si utilizza G1GC nello scenario peggiore (senza ottimizzazione, applicazione a thread singolo). Non è molto considerato un buon tempo di risposta e un basso utilizzo della memoria.

  • Quando si esegue da Tomcat che è multi-thread, le prestazioni complessive sono migliori del 30% e l'utilizzo della memoria è molto inferiore, così come i tempi di risposta sono molto inferiori.

Quindi, nel complesso, quando si utilizzano carichi di lavoro davvero vari, G1GC è un ottimo raccoglitore per Java 8 per applicazioni multi-thread e anche per single-threaded ci sono alcuni vantaggi.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.