Java Heap Space vs Stack – Allocare Memoria in Java

Qualche tempo fa ho scritto un paio di post su Java Garbage Collection e Java è Passato per Valore. Dopo di che ho ricevuto molte email per spiegare su Java Heap Space, Java Stack Memory, Allocamento Memoria in Java e quali sono le differenze tra loro. Vedrai molti riferimenti a Heap e Stack memory in libri e tutorial su Java e Java EE, ma difficilmente una spiegazione completa di cosa sia la memoria heap e stack in termini di programmazione.

Java Heap Space

Lo spazio di heap di Java è utilizzato dal runtime di Java per allocare memoria agli oggetti e alle classi JRE. Ogni volta che creiamo un oggetto, viene sempre creato nello spazio di heap. La Garbage Collection viene eseguita sulla memoria di heap per liberare la memoria utilizzata dagli oggetti che non hanno alcun riferimento. Qualsiasi oggetto creato nello spazio di heap ha accesso globale e può essere referenziato da qualsiasi punto dell’applicazione.

Java Stack Memory

La memoria Stack di Java viene utilizzata per l’esecuzione di un thread. Contiene valori specifici del metodo che sono di breve durata e riferimenti ad altri oggetti nello heap a cui il metodo fa riferimento. La memoria Stack viene sempre referenziata in ordine LIFO (Last-In-First-Out). Ogni volta che un metodo viene invocato, viene creato un nuovo blocco nella memoria stack per il metodo al fine di contenere valori primitivi locali e riferimenti ad altri oggetti nel metodo. Appena il metodo termina, il blocco diventa inutilizzato e diventa disponibile per il prossimo metodo. La dimensione della memoria Stack è molto inferiore rispetto alla memoria Heap.

Heap e memoria Stack in un programma Java

Comprendiamo l’uso della memoria Heap e Stack con un semplice programma.

package com.journaldev.test;

public class Memory {

	public static void main(String[] args) { // Line 1
		int i=1; // Line 2
		Object obj = new Object(); // Line 3
		Memory mem = new Memory(); // Line 4
		mem.foo(obj); // Line 5
	} // Line 9

	private void foo(Object param) { // Line 6
		String str = param.toString(); //// Line 7
		System.out.println(str);
	} // Line 8

}

L’immagine sottostante mostra la memoria Stack e Heap in relazione al programma sopra e come vengono utilizzate per memorizzare variabili primitive, oggetti e variabili di riferimento. Esaminiamo i passaggi dell’esecuzione del programma.

  • Appena eseguiamo il programma, carica tutte le classi Runtime nello spazio Heap. Quando il metodo main() viene trovato alla riga 1, Java Runtime crea la memoria stack da utilizzare dal thread del metodo main().
  • Stiamo creando una variabile locale primitiva alla riga 2, quindi viene creata e memorizzata nella memoria stack del metodo main().
  • Poiché stiamo creando un oggetto alla terza riga, esso viene creato nella memoria heap e la memoria stack contiene il riferimento ad esso. Un processo simile si verifica quando creiamo l’oggetto Memory alla quarta riga.
  • Ora, quando chiamiamo il metodo foo() alla quinta riga, viene creato un blocco nella parte superiore dello stack da utilizzare dal metodo foo(). Poiché Java è passato per valore, viene creato un nuovo riferimento all’oggetto nel blocco dello stack di foo() alla sesta riga.
  • A string is created in the 7th line, it goes in the String Pool in the heap space and a reference is created in the foo() stack space for it.
  • Il metodo foo() termina all’ottava riga, momento in cui il blocco di memoria allocato per foo() nello stack viene liberato.
  • Alla nona riga, il metodo main() termina e la memoria stack creata per il metodo main() viene distrutta. Inoltre, il programma termina a questa riga, quindi Java Runtime libera tutta la memoria e termina l’esecuzione del programma.

Differenza tra Heap Space e Stack Memory in Java

Basandoci sulle spiegazioni precedenti, possiamo facilmente concludere le seguenti differenze tra la memoria Heap e quella dello stack.

  1. La memoria Heap è utilizzata da tutte le parti dell’applicazione, mentre la memoria dello stack è utilizzata solo da un thread di esecuzione.
  2. Quando un oggetto viene creato, viene sempre memorizzato nello spazio Heap e la memoria stack contiene il riferimento ad esso. La memoria stack contiene solo variabili primitive locali e variabili di riferimento agli oggetti nello spazio heap.
  3. Gli oggetti memorizzati nello heap sono globalmente accessibili, mentre la memoria stack non può essere accessibile da altri thread.
  4. La gestione della memoria nello stack avviene in modo LIFO, mentre è più complessa nella memoria Heap perché è utilizzata globalmente. La memoria Heap è divisa in Young-Generation, Old-Generation, ecc., ulteriori dettagli su Garbage Collection di Java.
  5. La memoria stack è di breve durata, mentre la memoria heap vive dall’inizio alla fine dell’esecuzione dell’applicazione.
  6. Possiamo utilizzare -Xms e -Xmx come opzioni JVM per definire la dimensione iniziale e massima della memoria heap. Possiamo utilizzare -Xss per definire la dimensione della memoria stack.
  7. Quando la memoria stack è piena, il runtime di Java genera un’eccezione java.lang.StackOverflowError, mentre se la memoria heap è piena, genera un errore java.lang.OutOfMemoryError: Java Heap Space.
  8. La dimensione della memoria stack è molto inferiore rispetto a quella della memoria heap. A causa della semplicità nell’allocazione della memoria (LIFO), la memoria stack è molto veloce rispetto alla memoria heap.

Questo è tutto per Java Heap Space vs Stack Memory in termini di applicazioni Java. Spero che chiarisca i tuoi dubbi riguardo all’allocazione della memoria quando viene eseguito qualsiasi programma Java.

Riferimento: https://it.wikipedia.org/wiki/Modello_di_memoria_di_Java.

Source:
https://www.digitalocean.com/community/tutorials/java-heap-space-vs-stack-memory