logo

Gestione della memoria in Java

In Java, la gestione della memoria è il processo di allocazione e deallocazione di oggetti, chiamato gestione della memoria. Java esegue automaticamente la gestione della memoria. Java utilizza un sistema di gestione automatica della memoria chiamato a netturbino . Pertanto, non siamo tenuti a implementare la logica di gestione della memoria nella nostra applicazione. La gestione della memoria Java si divide in due parti principali:

    Struttura della memoria JVM Il funzionamento del Garbage Collector

Struttura della memoria JVM

JVM crea varie aree dati di runtime in un heap. Queste aree vengono utilizzate durante l'esecuzione del programma. Le aree di memoria vengono distrutte all'uscita della JVM, mentre le aree dati vengono distrutte all'uscita del thread.

Gestione della memoria in Java

Area Metodo

L'area del metodo è una parte della memoria heap condivisa tra tutti i thread. Viene creato all'avvio della JVM. Viene utilizzato per memorizzare la struttura della classe, il nome della superclasse, il nome dell'interfaccia e i costruttori. La JVM memorizza i seguenti tipi di informazioni nell'area del metodo:

  • Un nome completo di un tipo (es: String)
  • I modificatori del tipo
  • Il nome diretto della superclasse del tipo
  • Un elenco strutturato dei nomi completi delle super interfacce.

Area dell'heap

L'heap memorizza gli oggetti reali. Viene creato all'avvio della JVM. L'utente può controllare l'heap se necessario. Può essere di dimensione fissa o dinamica. Quando utilizzi una nuova parola chiave, la JVM crea un'istanza per l'oggetto in un heap. Mentre il riferimento di quell'oggetto viene memorizzato nello stack. Esiste un solo heap per ogni processo JVM in esecuzione. Quando l'heap si riempie, viene raccolta la spazzatura. Per esempio:

 StringBuilder sb= new StringBuilder(); 

L'istruzione precedente crea un oggetto della classe StringBuilder. L'oggetto alloca all'heap e il riferimento sb alloca allo stack. L'heap è diviso nelle seguenti parti:

stringa java
  • Generazione giovane
  • Spazio per i sopravvissuti
  • Vecchia generazione
  • Generazione permanente
  • Cache del codice

Tipo di riferimento

Esistono quattro tipi di riferimenti: Forte , Debole , Morbido , E Riferimento fantasma . La differenza tra i tipi di riferimenti è che gli oggetti nell'heap a cui si riferiscono sono idonei per il Garbage Collector in base a criteri diversi.

Riferimento forte: È molto semplice poiché lo usiamo nella nostra programmazione quotidiana. Qualsiasi oggetto a cui è associato un riferimento forte non è idoneo per la garbage collection. Possiamo creare un riferimento forte utilizzando la seguente istruzione:

 StringBuilder sb= new StringBuilder(); 

Riferimento debole: Non sopravvive dopo il successivo processo di garbage collection. Se non siamo sicuri di quando i dati verranno richiesti nuovamente. In questa condizione, possiamo creare un riferimento debole ad esso. Nel caso in cui il Garbage Collector esegua l'elaborazione, distrugge l'oggetto. Quando proviamo nuovamente a recuperare quell'oggetto, otteniamo un valore nullo. È definito in java.lang.ref.WeakReference classe. Possiamo creare un riferimento debole utilizzando la seguente istruzione:

 WeakReference reference = new WeakReference(new StringBuilder()); 

Riferimento morbido: Viene raccolto quando la memoria dell'applicazione è in esaurimento. Il garbage collector non raccoglie gli oggetti facilmente raggiungibili. Tutti gli oggetti con riferimenti soft vengono raccolti prima che venga generato un OutOfMemoryError. Possiamo creare un riferimento soft utilizzando la seguente istruzione:

 SoftReference reference = new SoftReference(new StringBuilder()); 

Riferimento fantasma: È disponibile in java.lang.ref pacchetto. È definito in java.lang.ref.PhantomReference classe. L'oggetto che ha solo un riferimento fantasma che li punta può essere raccolto ogni volta che il Garbage Collector desidera raccogliere. Possiamo creare un riferimento fantasma utilizzando la seguente istruzione:

 PhantomReference reference = new PhantomReference(new StringBuilder()); 

Area della pila

Stack Area viene generata quando viene creato un thread. Può essere di dimensione fissa o dinamica. La memoria dello stack viene allocata per thread. Viene utilizzato per memorizzare dati e risultati parziali. Contiene riferimenti a oggetti heap. Contiene anche il valore stesso anziché un riferimento a un oggetto dall'heap. Le variabili memorizzate nello stack hanno una certa visibilità, chiamata scope.

ciao mondo con Java

Telaio della pila: Lo stack frame è una struttura dati che contiene i dati del thread. I dati del thread rappresentano lo stato del thread nel metodo corrente.

  • Viene utilizzato per memorizzare risultati e dati parziali. Esegue inoltre il collegamento dinamico, la restituzione dei valori tramite metodi e l'invio di eccezioni.
  • Quando un metodo invoca, viene creato un nuovo frame. Distrugge il frame al termine dell'invocazione del metodo.
  • Ogni frame contiene il proprio array di variabili locali (LVA), stack di operandi (OS) e dati di frame (FD).
  • Le dimensioni di LVA, OS e FD determinate in fase di compilazione.
  • Solo un frame (il frame per il metodo di esecuzione) è attivo in qualsiasi punto di un dato thread di controllo. Questo frame è chiamato frame corrente e il suo metodo è noto come metodo corrente. La classe del metodo è chiamata classe corrente.
  • Il frame interrompe il metodo corrente, se il suo metodo richiama un altro metodo o se il metodo viene completato.
  • Il frame creato da un thread è locale a quel thread e non può essere referenziato da nessun altro thread.

Stack di metodi nativi

È noto anche come stack C. È uno stack per codice nativo scritto in un linguaggio diverso da Java. Java Native Interface (JNI) richiama lo stack nativo. Le prestazioni dello stack nativo dipendono dal sistema operativo.

Registri PC

A ogni thread è associato un registro Program Counter (PC). Il registro del PC memorizza l'indirizzo del mittente o un puntatore nativo. Contiene anche l'indirizzo delle istruzioni JVM attualmente in esecuzione.

Funzionamento del Garbage Collector

Panoramica del Garbage Collector

Quando un programma viene eseguito in Java, utilizza la memoria in diversi modi. L'heap è una parte della memoria in cui vivono gli oggetti. È l'unica parte della memoria coinvolta nel processo di garbage collection. È noto anche come mucchio di rifiuti da raccogliere. Tutta la garbage collection garantisce che l'heap abbia quanto più spazio libero possibile. La funzione del Garbage Collector è trovare ed eliminare gli oggetti che non possono essere raggiunti.

Allocazione degli oggetti

Quando un oggetto viene allocato, la JVM JRockit controlla la dimensione dell'oggetto. Distingue tra oggetti piccoli e grandi. Le dimensioni piccole e grandi dipendono dalla versione JVM, dalla dimensione dell'heap, dalla strategia di garbage collection e dalla piattaforma utilizzata. La dimensione di un oggetto è solitamente compresa tra 2 e 128 KB.

primo portatile

I piccoli oggetti vengono archiviati nella Thread Local Area (TLA), che è una parte libera dell'heap. TLA non si sincronizza con altri thread. Quando il TLA è pieno, richiede un nuovo TLA.

D'altra parte, gli oggetti di grandi dimensioni che non rientrano nel TLA vengono allocati direttamente nell'heap. Se un thread utilizza lo spazio giovane, viene archiviato direttamente nel vecchio spazio. L'oggetto di grandi dimensioni richiede una maggiore sincronizzazione tra i thread.

Cosa fa Java Garbage Collector?

JVM controlla il Garbage Collector. JVM decide quando eseguire la garbage collection. Possiamo anche richiedere alla JVM di eseguire il garbage collector. Ma non vi è alcuna garanzia in alcuna condizione che la JVM sia conforme. JVM esegue il Garbage Collector se rileva che la memoria si sta esaurendo. Quando il programma Java richiede il Garbage Collector, la JVM di solito soddisfa la richiesta in breve tempo. Non garantisce che le richieste vengano accettate.

Il punto da capire è che' quando un oggetto diventa idoneo per la garbage collection? '

cos'è Internet

Ogni programma Java ha più di un thread. Ogni thread ha il suo stack di esecuzione. C'è un thread da eseguire nel programma Java che è un metodo main(). Ora possiamo dire che un oggetto è idoneo per la garbage collection quando nessun thread attivo può accedervi. Il Garbage Collector considera l'oggetto idoneo per l'eliminazione. Se un programma ha una variabile di riferimento che fa riferimento a un oggetto, quella variabile di riferimento disponibile per il thread attivo, viene chiamato questo oggetto raggiungibile .

Qui sorge una domanda che ' Un'applicazione Java può esaurire la memoria? '

La risposta è si. Il sistema di raccolta dei rifiuti tenta di estrarre oggetti dalla memoria quando non sono in uso. Tuttavia, se si mantengono molti oggetti attivi, la garbage collection non garantisce che ci sia memoria sufficiente. Solo la memoria disponibile verrà gestita in modo efficace.

Tipi di raccolta dei rifiuti

Esistono cinque tipi di garbage collection:

    GC seriale:Utilizza l'approccio Mark and Sweep per le generazioni giovani e vecchie, che è GC minore e maggiore.GC parallelo:È simile al GC seriale, tranne per il fatto che genera N thread (il numero di core della CPU nel sistema) per la garbage collection di giovane generazione.Vecchio GC parallelo:È simile al GC parallelo, tranne per il fatto che utilizza più thread per entrambe le generazioni.Raccoglitore Concurrent Mark Sweep (CMS):Fa la raccolta dei rifiuti per la vecchia generazione. È possibile limitare il numero di thread nel raccoglitore CMS utilizzando XX:ParalleCMSThreads=Opzione JVM . È noto anche come raccoglitore di pausa bassa simultanea.Raccoglitore di rifiuti G1:È stato introdotto in Java 7. Il suo obiettivo è sostituire il raccoglitore CMS. È un raccoglitore parallelo, simultaneo e CMS. Non c’è spazio per le giovani e le vecchie generazioni. Divide l'heap in più heap di uguali dimensioni. Innanzitutto raccoglie le regioni con meno dati in tempo reale.

Algoritmo Mark and Sweep

JRockit JVM utilizza l'algoritmo mark e sweep per eseguire la garbage collection. Contiene due fasi, la fase di marcatura e la fase di spazzata.

Fase di contrassegno: Gli oggetti accessibili dai thread, dagli handle nativi e da altre origini root GC sono contrassegnati come attivi. Ogni albero di oggetti ha più di un oggetto radice. La radice GC è sempre raggiungibile. Quindi qualsiasi oggetto che abbia una radice di garbage collection alla radice. Identifica e contrassegna tutti gli oggetti in uso e il resto può essere considerato spazzatura.

Gestione della memoria in Java

Fase di scansione: In questa fase, l'heap viene attraversato per trovare lo spazio tra gli oggetti vivi. Queste lacune vengono registrate nell'elenco libero e sono disponibili per l'assegnazione di nuovi oggetti.

Sono disponibili due versioni migliorate di Mark and Sweep:

media vs media
    Mark e Sweep simultanei Marcatura parallela e spazzata

Mark e Sweep simultanei

Consente ai thread di continuare l'esecuzione durante gran parte della raccolta dei rifiuti. Esistono i seguenti tipi di marcatura:

    Marcatura iniziale:Identifica il set radice degli oggetti live. Viene eseguito mentre i thread sono in pausa.Marcatura simultanea:In questa marcatura vengono seguiti i riferimenti all'insieme delle radici. Trova e contrassegna il resto degli oggetti attivi in ​​un heap. Viene eseguito mentre il thread è in esecuzione.Marcatura pre-pulizia:Identifica le modifiche apportate mediante marcatura simultanea. Altri oggetti vivi segnati e ritrovati. Viene eseguito mentre i thread sono in esecuzione.Votazione finale:Identifica le modifiche apportate mediante marcatura di pre-pulizia. Altri oggetti vivi segnati e ritrovati. Viene eseguito mentre i thread sono in pausa.

Marcatura parallela e spazzata

Utilizza tutta la CPU disponibile nel sistema per eseguire la garbage collection il più velocemente possibile. È anche chiamato Garbage Collector parallelo. I thread non vengono eseguiti quando viene eseguita la Garbage Collection parallela.

Pro di Mark e Sweep

  • È un processo ricorrente.
  • È un ciclo infinito.
  • Nessun sovraccarico aggiuntivo consentito durante l'esecuzione di un algoritmo.

Contro di Mark e Sweep

  • Arresta la normale esecuzione del programma mentre viene eseguito l'algoritmo di garbage collection.
  • Viene eseguito più volte su un programma.