Per configurare i parametri JVM per minimizzare le pause della Garbage Collection (GC), è importante comprendere le operazioni fondamentali di diversi collezionisti di immondizia e i meccanismi di accordatura disponibili nel JVM. Il processo di configurazione prevede la selezione di un algoritmo di raccolta della spazzatura appropriato, la messa a punto delle dimensioni del heap, la configurazione di obiettivi di tempo di pausa, i parametri di threading e l'ottimizzazione delle regioni di memoria. Di seguito è riportata una sintesi dettagliata della messa a punto JVM per ridurre al minimo le pause GC in base a fonti autorevoli e migliori pratiche:
Scegliere il collettore di immondizia giusto
JVM offre più algoritmi di raccolta dei rifiuti, ciascuno con caratteristiche diverse per quanto riguarda il throughput, i tempi di pausa e l'utilizzo delle risorse:
- Serial GC: utilizza un singolo thread per GC. Ferma tutti i thread dell'applicazione durante la raccolta, con conseguenti pause lunghe. In genere non è adatto per ridurre al minimo le pause in applicazioni più grandi.
- GC parallelo: utilizza più thread per eseguire la raccolta della spazzatura, riducendo i tempi di pausa rispetto al GC seriale sfruttando più core CPU. È orientato alla throughput ma fa comunque una pausa i thread dell'applicazione durante GC.
- CONCURNENTE MARK-SWEEP (CMS) GC: svolge gran parte del lavoro di raccolta della spazzatura contemporaneamente all'applicazione, riducendo significativamente i tempi di pausa facendo solo brevemente l'applicazione in fasi GC specifiche. È adatto per applicazioni a bassa latenza.
- Garbage First (G1) GC: divide il mucchio in regioni e si concentra sulla raccolta di regioni con la maggior parte della spazzatura. Mira a fornire tempi di pausa prevedibili e un buon rendimento miscelando fasi simultanee e parallele. È spesso l'impostazione predefinita nelle moderne versioni JVM.
- Shenandoah e ZGC: questi collezionisti a bassa latenza svolgono tutto o la maggior parte del lavoro GC contemporaneamente, mirando a pause molto brevi o quasi impercettibili, adatti a grandi cumuli e applicazioni altamente reattive.
La scelta del collettore giusto dipende dai requisiti dell'applicazione come il tempo di pausa tollerato massimo, la dimensione del heap e le caratteristiche del carico di lavoro.
Configurazione della dimensioneheap
La dimensione del heap ha un impatto diretto sulla frequenza GC e sulla pausa:
-Imposta dimensione iniziale e massima di heap uguale: usando `-xms` e` -xmx` con lo stesso valore evita il ridimensionamento del heap, che può introdurre pause durante il runtime.
- dimensioni del mucchio adeguate: un mucchio sotto-allocazione provoca collezioni frequenti, aumentando le pause. Tuttavia, l'eccessiva allocazione porta a cicli GC più lunghi. Trova un saldo in base alle esigenze di memoria dell'applicazione.
- Monitorare i registri GC e le metriche di utilizzo dell'heap per sintonizzare in modo appropriato la dimensione del heap.
Controllo del tempo di pausa GC
JVM fornisce parametri per fissare obiettivi per i tempi di pausa GC massimi:
- `-xx: maxGCPauseMillis =`: imposta un tempo di pausa massimo target in millisecondi per il collettore per cercare di incontrarsi. Sebbene non garantito, il JVM tenta di regolare la throughput e il lavoro GC per evitare di superare questo tempo di pausa.
- Utilizzare questo parametro con G1 GC o altri collezionisti che supportano gli obiettivi di pausa per guidare il JVM nel bilanciamento della throughput e della latenza.
threading e parallelismo
Sfruttare più thread durante la collezione di immondizia riduce le durate di pausa:
- `-xx: parallelgcthreads =`: imposta il numero di thread utilizzati durante le fasi parallele di GC. Più thread possono ridurre il tempo di pausa ma possono anche aumentare l'utilizzo della CPU.
- `-xx: ConcGCThreads =`: per collezionisti simultanei come CMS e G1, imposta il numero di thread che eseguono fasi simultanee.
- Il conteggio ottimale dei thread dovrebbe allinearsi con il numero di core della CPU disponibili e il carico di lavoro; I thread di iscrizione eccessiva possono degradare le prestazioni.
Tuning di piccole e vecchie dimensioni di generazione
Il heap è in genere diviso in generazioni giovani e vecchi. Sintonizzare le loro dimensioni influisce sul comportamento GC:
- Dimensione delle giovani generazioni: la più grande generazione di giovani generazioni riduce la frequenza di GC minori ma aumenta i tempi di pausa GC minori. Regola in base al tasso di allocazione degli oggetti.
- Dimensione di vecchia generazione: influenza la frequenza con cui i GC principali/completi funzionano e la loro durata.
- G1 GC divide il heap in molte regioni equamente di dimensioni e gestisce la dimensione in modo dinamico, ma consente le soglie di iniziazione di messa a punto con parametri come `-xx: InitiatingHeapCupancyPercent`.
parametri specifici del collettore di garbage
Per G1 GC, comunemente usato nei JVM moderni:
- `-xx:+useg1gc`: abilita g1 gc.
- `-xx: maxGCPAuseMillis =`: pausa Time Target.
- `-xx: InitiatingHeapCupancyPercent =`: inizia la marcatura simultanea quando il mucchio raggiunge questa occupazione.
- `-xx:+usestringdeduplication`: riduce l'impronta di memoria deduplicando le stringhe.
- Evita di impostare esplicitamente la dimensione della generazione delle giovani, in quanto può interferire con gli obiettivi di pausa di G1.
Per CMS GC:
- `-xx:+useconcmarksweepgc`: abilita CMS.
-Sortoscarsi la messa a fuoco sulla riduzione delle pause di arresto globale del mondo regolando la soglia di iniziazione e il conteggio dei fili.
Per GC parallelo (orientato alla throughput):
-`-xx:+usaparallelgc` e` -xx:+usaparalleloldgc`: abilita GC parallelo per giovani e vecchie generazioni.
- Sintonizza il numero di thread GC con `-xx: parallelgcthreads`.
riducendo il tasso di allocazione degli oggetti
Ridurre la velocità con cui vengono creati nuovi oggetti riduce la pressione GC:
- Profilo e ottimizza il codice per ridurre al minimo la creazione di oggetti non necessaria.
- Usa il pooling e il riutilizzo degli oggetti quando possibile.
- Regola i parametri JVM per regolare le regioni di memoria interna per modelli di allocazione di oggetti migliori.
Evita le chiamate GC esplicite
- Disabilita le chiamate GC esplicite dal codice dell'applicazione o dagli strumenti esterni che possono attivare pause GC complete utilizzando `-xx:+DisableExplicitGC`.
monitoraggio e registrazione
Per capire e sintonizzare il comportamento GC, abilitare la registrazione GC dettagliata:
- Usa `-xlog: GC*` in JVMS Supporting Unified Logging (Java 9+).
-In JVMS più vecchio, usa `-xx:+printgcdetails -xx:+printgcdatestamps -xloggc:`.
Analizzare i registri per identificare le cause e sintonizzarsi di conseguenza.
Raccomandazioni generali
- Inizia a sintonizzare con una lavagna pulita rimuovendo gli argomenti JVM obsoleti.
- Test cambiamenti in un ambiente simile alla produzione.
- Utilizzare strumenti come il registratore di volo Java, VisualVM o i profili commerciali per raccogliere dati di utilizzo GC e di memoria.
- Iterare i passaggi di accordatura basati sui tempi di pausa GC osservati, il throughput e la reattività dell'applicazione.
In sintesi, minimizzare le pause della raccolta della spazzatura JVM comporta la selezione del collettore di immondizia appropriato (preferibilmente G1, ZGC o Shenandoah per i requisiti di pausa a bassa pausa), dimensionando correttamente il heap e le generazioni, impostando gli obiettivi di tempo della pausa, tune di tuni thread di concorrenza, minimizzando il tasso di allocazione degli oggetti, disabilitando il GC esplicito e il monitoraggio attento. Le specifiche dipenderanno dal carico di lavoro dell'applicazione, dalla dimensione del heap, dalla versione JVM e dalle caratteristiche hardware. Le regolazioni devono essere apportate in modo incrementale e validate con strumenti di monitoraggio e registri GC dettagliati per raggiungere il bilancio desiderato del throughput e del tempo di pausa.
Questo approccio garantisce che la raccolta della spazzatura di JVM funzioni in modo efficiente con interruzioni minime delle prestazioni dell'applicazione.