Nella maggior parte dei contesti, "dinamico" si riferisce alla memoria allocata dal programmatore esplicitamente , a differenza della memoria allocata come parte normale dell'inserimento di una funzione (riservando spazio per i parametri, variabili locali , eccetera.).
Prendiamo come esempio la seguente funzione C:
void foo(int x, int y)
{
int z;
char *str = NULL;
...
str = malloc(sizeof *str * y);
...
free(str);
}
Quando entriamo nella funzione, lo spazio viene automaticamente prenotato nello stack per x
, y
, z
e il puntatore str
(ricorda che gli elementi dello stack sono allocati nell'ultimo, primo ordine ). Inoltre, la quantità di spazio da riservare per ogni oggetto è fissata al momento della compilazione (in base alle dimensioni dei rispettivi tipi). Se guardi il frame dello stack, sarà simile a questo (supponiamo che int
e char *
siano tutte della stessa dimensione):
%pr_e%
Quando si esce dalla funzione, tutti gli elementi tra "STACK BOTTOM" e "STACK TOP" verranno spuntati (deallocati).
Non controllo l'allocazione della memoria a questo livello; tutto questo viene fatto automaticamente per me quando entro e esco dalla funzione. Tuttavia, all'interno della funzione voglio allocare memoria per str
a cui puntare. Inoltre, la quantità di memoria che desidero allocare non è fissa, ma viene determinata in fase di esecuzione dal valore del parametro y
. La chiamata malloc
riserva un po 'di memoria dall'heap (un'area di memoria distinta dallo stack, che viene gestita in modo diverso) e assegna l'indirizzo di quella memoria a str
. Quella memoria rimane allocata finché non la rilascio esplicitamente con una chiamata a free
; se non lo faccio prima che la funzione esca, la variabile str
variabile viene deallocata (significa che perdo il mio riferimento a quel blocco assegnato in modo dinamico), ma la memoria a cui punta non lo fa (questo è noto come una perdita di memoria, una volta che ho perso il mio riferimento al blocco dinamico, non posso free
esso).
Java si comporta in modo leggermente diverso:
+--------+
| | <-- y STACK BOTTOM
+--------+
| | <-- x
+--------+
| | <-- z
+--------+
| | <--str STACK TOP
+--------+
Simile a C, Java riserva spazio nello stack per ogni x
, y
, z
e un puntatore str
(sì, Java usa i puntatori sotto il cofano, non lo fa esporre le operazioni del puntatore al programmatore). Simile a C, l'operatore new
riserva la memoria per l'oggetto String
sull'heap in fase di runtime. A differenza di C, Java monitora gli oggetti sull'heap per vedere se vengono referenziati da chiunque (come la variabile str
). Una volta che la funzione Java termina, tutti i riferimenti alla memoria dinamica cessano di esistere e un garbage collector automatico alla fine rilascia la memoria, quindi non devo liberarlo esplicitamente (infatti, Java non fornisce un equivalente al free
funzione).