Java Virtual Machine - Garbage Collection
Il ciclo di vita di un oggetto Java è gestito dalla JVM. Una volta che un oggetto è stato creato dal programmatore, non dobbiamo preoccuparci del resto del suo ciclo di vita. La JVM troverà automaticamente quegli oggetti che non sono più in uso e recupererà la loro memoria dall'heap.
La raccolta dei rifiuti è un'operazione importante che JVM fa e ottimizzarla per le nostre esigenze può fornire un enorme aumento delle prestazioni della nostra applicazione. Esistono numerosi algoritmi di garbage collection forniti dalle moderne JVM. Dobbiamo essere consapevoli delle esigenze della nostra applicazione per decidere quale algoritmo utilizzare.
Non è possibile deallocare un oggetto a livello di programmazione in Java, come si può fare in linguaggi non GC come C e C ++. Pertanto, non è possibile avere riferimenti pendenti in Java. Tuttavia, potresti avere riferimenti nulli (riferimenti che fanno riferimento a un'area di memoria in cui la JVM non memorizzerà mai oggetti). Ogni volta che viene utilizzato un riferimento null, la JVM genera un'eccezione NullPointerException.
Si noti che sebbene sia raro trovare perdite di memoria nei programmi Java grazie al GC, si verificano. Creeremo una perdita di memoria alla fine di questo capitolo.
I seguenti GC vengono utilizzati nelle moderne JVM
- Collettore seriale
- Raccoglitore di throughput
- Collettore CMS
- Collettore G1
Ciascuno degli algoritmi di cui sopra svolge la stessa operazione: trovare oggetti che non sono più in uso e recuperare la memoria che occupano nell'heap. Uno degli approcci ingenui a questo sarebbe contare il numero di riferimenti che ogni oggetto ha e liberarlo non appena il numero di riferimenti diventa 0 (questo è anche noto come conteggio dei riferimenti). Perché questo è ingenuo? Considera un elenco collegato circolare. Ciascuno dei suoi nodi avrà un riferimento ad esso, ma l'intero oggetto non viene referenziato da nessuna parte e dovrebbe essere liberato, idealmente.
La JVM non solo libera la memoria, ma unisce anche piccoli mandrini di memoria in quelli più grandi. Questo viene fatto per prevenire la frammentazione della memoria.
In una semplice nota, un tipico algoritmo GC svolge le seguenti attività:
- Trovare oggetti inutilizzati
- Liberare la memoria che occupano nel mucchio
- Unendo i frammenti
Il GC deve arrestare i thread dell'applicazione mentre è in esecuzione. Questo perché sposta gli oggetti in giro quando viene eseguito e, pertanto, quegli oggetti non possono essere utilizzati. Tali fermate sono chiamate pause "stop-the-world" e ridurre al minimo la frequenza e la durata di queste pause è ciò a cui miriamo durante la regolazione del nostro GC.
Coalescenza della memoria
Di seguito viene mostrata una semplice dimostrazione della coalescenza della memoria
La parte ombreggiata sono oggetti che devono essere liberati. Anche dopo che tutto lo spazio è stato recuperato, possiamo allocare solo un oggetto di dimensione massima = 75Kb. Questo è anche dopo che abbiamo 200 KB di spazio libero come mostrato di seguito