JavaRush /Java Blog /Random-IT /Pausa caffè #210. Tutti i tipi di Garbage Collector in Ja...

Pausa caffè #210. Tutti i tipi di Garbage Collector in Java che dovresti conoscere

Pubblicato nel gruppo Random-IT
Fonte: Hackernoon Attraverso questo post imparerai i punti di forza e di debolezza di ogni tipo di garbage collector utilizzato nello sviluppo Java. Pausa caffè #210.  Tutti i tipi di Garbage Collector in Java che dovresti conoscere - 1La domanda su Garbage Collector (GC) si sente in quasi tutte le interviste. Così ho deciso di raccogliere tutte le informazioni necessarie su di loro utilizzando il mio principio preferito: breve e semplice. Innanzitutto, iniziamo con lo scopo della CG e il motivo per cui abbiamo bisogno di più tipi di garbage collector. In linguaggi come C, dobbiamo archiviare le informazioni sugli oggetti in memoria e scrivere molto codice standard per liberare quella memoria. Naturalmente, le perdite di memoria sono comuni in tali programmi. Java risolve il problema delle perdite di memoria utilizzando un garbage collector. E tu, come sviluppatore, dovresti sapere quale garbage collector è meglio usare. Molto dipende da dove e come viene eseguito il tuo programma. Potrebbe funzionare su hardware debole o con un gran numero di oggetti oppure il tuo programma deve essere molto veloce. In base a queste condizioni, dovresti ottimizzare il tuo garbage collector per ottenere le prestazioni desiderate. Quindi, cominciamo.

Come la JVM gestisce la memoria

La Java Virtual Machine (JVM) divide la memoria in due aree: l'heap, che memorizza i dati dell'applicazione, e il non-heap, che memorizza il codice del programma e altri dati. Rivolgiamo la nostra attenzione all'area dell'heap. Qui è dove il nostro programma crea nuovi oggetti. Tutti i garbage collector si basano sul fatto che molti programmi utilizzano oggetti effimeri. Cioè, questi oggetti sono stati creati, poi hanno svolto la loro funzione e non sono più necessari. La maggior parte di tali oggetti. Ma alcuni oggetti vivono molto più a lungo, forse addirittura per tutta la durata del programma. È qui che nasce l'idea di dividere gli oggetti in generazioni giovani e vecchie. E dobbiamo controllare molto spesso le generazioni più giovani. Il fatto è che i processi di raccolta dei rifiuti si dividono in pulizie minori, che interessano solo le generazioni più giovani, e pulizie complete, che possono interessare entrambe le generazioni. Ricorda che il garbage collector è un programma. E richiede tempo e risorse dal tuo computer per funzionare. Ciò influisce anche sulla nostra applicazione. Come influisce? Ad esempio, per eseguire la garbage collection, la JVM mette in pausa la nostra applicazione. Questa è chiamata pausa Stop-The-World (STW). Durante questo periodo, tutti i thread dell'applicazione vengono sospesi. Ma l'applicazione interna ne è completamente ignara. Per l'applicazione il tempo scorre in modo uniforme. Perché è così brutto? Immagina di scrivere una sorta di domanda di scambio o una domanda per un pilota automatico per aereo. La tua applicazione potrebbe entrare in modalità di sospensione per un secondo e la natura del problema potrebbe cambiare radicalmente. Cioè, la pausa è un parametro significativo per ogni garbage collector. La successiva proprietà fondamentale del Garbage Collector è il tempo totale impiegato nella raccolta dei rifiuti in relazione al tempo totale di esecuzione del programma. Cosa significa questo e perché è così importante? Invece di una grande fase “Stop-The-World”, possiamo scegliere un algoritmo con tante piccole pause. Sono preferibili piccole pause, ma nulla è gratis. In questo caso paghiamo aumentando il tempo totale di esecuzione del programma. E dobbiamo tenere conto anche di questo. Il parametro successivo è la quantità di risorse hardware. Ogni raccoglitore necessita di memoria per archiviare le informazioni sugli oggetti e di un processore per eseguire la pulizia. L'ultimo parametro è la velocità. L'efficienza della Garbage Collection si riferisce alla rapidità ed efficienza con cui il Garbage Collector (GC) recupera la memoria che non viene più utilizzata da un programma. Tutti questi parametri influenzano l'algoritmo, che può liberare memoria il più rapidamente possibile consumando risorse minime. Diamo un'occhiata ai netturbini a nostra disposizione. Per il colloquio è necessario conoscere i primi cinque. Gli altri due sono molto più difficili.

G.C. seriale

Serial GC è il garbage collector della Java Virtual Machine ed è stato utilizzato fin dall'inizio di Java. È utile per programmi con un piccolo heap e in esecuzione su macchine meno potenti. Questo garbage collector divide l'heap in regioni, che includono Eden e Survivor. La regione dell'Eden è il pool da cui viene inizialmente allocata la memoria per la maggior parte degli oggetti. Survivor è un pool contenente oggetti sopravvissuti alla raccolta dei rifiuti nella regione dell'Eden. Man mano che l'heap si riempie, gli oggetti vengono spostati tra le regioni Eden e Survivor. La JVM monitora costantemente il movimento degli oggetti nelle regioni dei Sopravvissuti e seleziona una soglia appropriata per il numero di tali movimenti, dopo la quale gli oggetti vengono spostati nella regione Tenered. Quando non c'è abbastanza spazio nella regione Tenered, subentra la raccolta completa dei rifiuti, lavorando su oggetti di entrambe le generazioni. Il vantaggio principale di questo garbage collector è il basso fabbisogno di risorse, quindi per eseguire la raccolta è sufficiente un processore a basso consumo. Lo svantaggio principale del Serial GC sono le lunghe pause durante la garbage collection, soprattutto quando si tratta di grandi quantità di dati.

CG parallelo

Un garbage collector parallelo (Parallel CG) è simile a un costruttore sequenziale. Include l'elaborazione parallela di alcune attività e la possibilità di ottimizzare automaticamente le impostazioni delle prestazioni. Parallel GC è un garbage collector di Java Virtual Machine basato sulle idee di Serial GC, ma con parallelismo e intelligenza aggiuntivi. Se il computer ha più di un core del processore, la versione precedente della JVM seleziona automaticamente Parallel GC. L'heap qui è diviso nelle stesse regioni di Serial GC: Eden, Survivor 0, Survivor 1 e Old Gen (Tenered). Tuttavia, più thread partecipano in parallelo alla garbage collection e il raccoglitore può adattarsi ai parametri prestazionali richiesti. Ogni thread del collector ha un'area di memoria che deve essere cancellata. Parallel GC dispone inoltre di impostazioni volte a raggiungere l'efficienza di garbage collection richiesta. Il raccoglitore utilizza le statistiche delle raccolte di rifiuti precedenti per ottimizzare le impostazioni delle prestazioni per le raccolte future. Parallel GC fornisce la regolazione automatica dei parametri prestazionali e riduce i tempi di pausa della compilazione, ma presenta un piccolo inconveniente sotto forma di frammentazione della memoria. È adatto alla maggior parte delle applicazioni, ma per programmi più complessi è meglio scegliere implementazioni del garbage collector più avanzate. Pro: in molti casi più veloce del GC seriale. Ha una buona velocità. Contro: consuma più risorse e le pause possono essere piuttosto lunghe, ma possiamo regolare la durata massima della pausa di Stop-The-World.

Spazzata di segni simultanea

Il Garbage Collector Concurrent Mark Sweep (CMS) mira a ridurre la durata massima della pausa eseguendo alcune attività di Garbage Collection contemporaneamente ai thread dell'applicazione. Questo garbage collector è adatto alla gestione di grandi quantità di dati in memoria. Concurrent Mark Sweep (CMS) è un'alternativa a Parallel GC nella Java Virtual Machine (JVM). È destinato alle applicazioni che richiedono l'accesso a più core del processore e sono sensibili alle pause Stop-The-World. Il CMS esegue le fasi di garbage collection in parallelo con il programma principale, consentendone l'esecuzione senza interruzioni. Utilizza la stessa organizzazione della memoria dei raccoglitori Seriale e Parallelo, ma non attende che l'area Tenered venga riempita prima di eseguire l'eliminazione della vecchia generazione. Viene invece eseguito in background e tenta di mantenere compatta la regione di ruolo. Concurrent Mark Sweep inizia con una fase di marcatura iniziale che interrompe brevemente i thread principali dell'applicazione e marca tutti gli oggetti accessibili da root. I thread principali dell'applicazione riprendono quindi e il CMS inizia a cercare tutti gli oggetti attivi accessibili tramite collegamenti dagli oggetti root contrassegnati. Dopo aver contrassegnato tutti gli oggetti viventi, il collezionista cancella la memoria degli oggetti morti in diversi thread paralleli. Uno dei vantaggi di un CMS è la sua attenzione alla riduzione dei tempi di inattività, che è fondamentale per molte applicazioni. Tuttavia, richiede sacrifici in termini di risorse della CPU e larghezza di banda complessiva. Inoltre il CMS non comprime gli oggetti della vecchia generazione, il che porta alla frammentazione. Lunghe pause dovute a possibili guasti alla modalità parallela possono essere una spiacevole sorpresa (anche se non si verificano spesso). Se la memoria è sufficiente, il CMS può evitare tali pause. Pro: veloce. Ha piccole pause da Ferma il mondo. Contro: consuma più memoria; se la memoria non è sufficiente alcune pause potrebbero essere lunghe. Non molto buono se l'applicazione crea molti oggetti.

Prima la spazzatura

Garbage-First (G1) è considerato un'alternativa a un CMS, in particolare per le applicazioni server eseguite su server multiprocessore e che gestiscono grandi set di dati. Il Garbage Collector G1 converte la memoria in più regioni di uguali dimensioni, ad eccezione delle regioni enormi (create unendo regioni regolari per ospitare oggetti di grandi dimensioni). Le regioni non devono essere organizzate in fila e possono cambiare la loro appartenenza generazionale. Piccole epurazioni vengono eseguite periodicamente per la generazione più giovane e spostano gli oggetti nelle regioni dei Sopravvissuti o li aggiornano alla generazione più anziana e li trasferiscono in Tenered. La pulizia viene effettuata solo in quelle regioni dove è necessario evitare di superare il tempo desiderato. Il collezionista stesso prevede e seleziona le regioni con la maggiore quantità di rifiuti da pulire. Le scansioni complete utilizzano un ciclo di marcatura per creare un elenco di oggetti attivi che viene eseguito in parallelo con l'applicazione principale. Dopo il ciclo di marcatura, G1 passa all'esecuzione di epurazioni miste, che aggiungono regioni di generazione precedente all'insieme di regioni di generazione più giovane da eliminare. Il Garbage Collector G1 è considerato più accurato del Collector CMS nel prevedere le dimensioni delle pause e distribuisce meglio la Garbage Collection nel tempo per evitare lunghi tempi di inattività delle applicazioni, soprattutto con dimensioni heap di grandi dimensioni. Inoltre non frammenta la memoria come il raccoglitore CMS. Tuttavia, il raccoglitore G1 richiede più risorse della CPU per essere eseguito in parallelo con il programma principale, il che riduce il throughput dell'applicazione. Pro: Funziona meglio del CMS. Ha pause più brevi. Contro: consuma più risorse della CPU. Inoltre consuma più memoria se abbiamo molti oggetti abbastanza grandi (più di 500 KB) perché inserisce tali oggetti in un'unica regione (1-32 MB).

EpsilonGC

Epsilon GC è progettato per situazioni in cui non è richiesta la raccolta dei rifiuti. Non esegue la garbage collection, ma utilizza TLAB (buffer di allocazione locale del thread) per allocare nuovi oggetti: piccoli buffer di memoria richiesti dai singoli thread dall'heap. Oggetti enormi che non rientrano nel buffer richiedono blocchi di memoria appositamente per se stessi. Quando il GC Epsilon esaurisce le risorse, viene generato un OutOfMemoryError e il processo termina. I vantaggi di Epsilon GC includono minori requisiti di risorse e un'allocazione di memoria più rapida per le applicazioni che creano tutti gli oggetti di cui hanno bisogno all'avvio o eseguono applicazioni di breve durata che non utilizzano tutta la memoria allocata. Epsilon GC può anche aiutare ad analizzare i requisiti di risorse che altri garbage collector aggiungono alla tua applicazione. Punti positivi: Molto veloce. Contro: Non cancella gli oggetti :) I prossimi due raccoglitori sono i più avanzati nel loro genere, ma anche i più complessi. Li considereremo quindi brevemente.

ZGC

ZGC può mantenere una latenza inferiore al millisecondo anche quando si tratta di gestire enormi quantità di dati. ZGC è un garbage collector sviluppato da Oracle per Java progettato per fornire un throughput elevato e una bassa latenza durante l'elaborazione di heap di grandi dimensioni (fino a 16 TB). ZGC si basa sui principi della memoria virtuale e utilizza diversi contrassegni di colore per tenere traccia dello stato degli oggetti durante la raccolta dei rifiuti. Pro: le pause sono inferiori a un millisecondo, anche su heap di grandi dimensioni, il che è molto utile per le applicazioni che richiedono tempi brevi di elaborazione delle query. Funziona con heap molto grandi con una buona produttività. ZGC può comprimere la memoria heap durante la garbage collection. Contro: utilizzo elevato della CPU e requisiti di prestazioni significativi, che possono rallentare i tempi di avvio delle applicazioni.

Shenandoah G.C.

Shenandoah GC è un altro garbage collector con pause brevi indipendentemente dalla dimensione dell'heap. Questo garbage collector è sviluppato da Red Hat. È progettato per ridurre al minimo il tempo impiegato da un'applicazione nella raccolta dei rifiuti. Come ZGC, è un raccoglitore parallelo, il che significa che viene eseguito mentre l'applicazione è in esecuzione, riducendo al minimo le pause. Shenandoah GC utilizza "puntatori di inoltro" per spostare gli oggetti durante la garbage collection. Dispone inoltre di una tecnica chiamata “rimozione della barriera di carico” per migliorare le prestazioni. Pro: Shenandoah GC può raggiungere tempi di pausa brevi, spesso inferiori a 10 ms, anche per heap enormi. Buona produttività. Contro: carico elevato del processore e difficoltà a lavorare con carichi pesanti.

Conclusione

I garbage collector sono uno dei compiti più difficili nella programmazione. Nuovi sviluppi vengono costantemente effettuati in questa direzione. Sebbene sia raro che i programmatori modifichino il GC, è comunque necessario avere almeno una conoscenza approfondita di come funziona lo strumento di raccolta dei rifiuti.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION