Slide sulla gestione dinamica della memoria. Il Pdf è un documento che illustra i meccanismi di allocazione e deallocazione automatica della memoria e il funzionamento del Garbage Collector in Java, ideale per studenti universitari di Informatica.
Mostra di più18 pagine


Visualizza gratis il Pdf completo
Registrati per accedere all’intero documento e trasformarlo con l’AI.
Per comprendere la tecnica dell'allocazione dinamica della memoria, dobbiamo partire dal modo in cui un programma viene allocato in memoria centrale. Generalmente, la memoria di un PC e suddivisa in quattro parti Il segmento codice contiene le istruzioni del programma. : Il segmento dati contiene le variabili statiche globali (definite a tempo di compilazione). Tali variabili possono essere utilizzate durante tutto il tempo di esecuzione di un programma, indipendentemente dal fatto che si utilizzino o meno sottoprogrammi. La quantità di memoria statica può essere definita a priopri osservando la parte dichiarativa del codice del programma.
: II segmento stack contiene i dati utilizzati dai sottoprogrammi (variabili locali statiche). La sua dimensione cresce dinamicamente durante l'esecuzione del programma principale a mano a mano che vengono richiamati i vari sottoprogrammi. Quando viene richiamato un sottoprogramma, viene allocata la memoria necessaria a contenere le variabili locali e i parametri passati per valore. Al termine del sottoprogramma viene liberata l'area di memoria occupata per esso, distruggendone il contenuto. Il primo sottoprogramma che termina è sempre l'ultimo richiamato
II segmento heap (il termine inglese heap significa letteralmente "accumulo" o "mucchio ") contiene le variabili dinamiche, inclusi gli oggetti creati con l'operatore NUOVO visto nella programmazione a oggetti
Heap Stack Segmento dati Segmento codice
Qualunque programma ha bisogno di uno spazio di memoria per il codice e per i dati. Se il programma non utilizza dei sottoprogrammi, impiega soltanto risorse globali e, pertanto, occuperà sempre la stessa porzione di memoria (vedi la figura qui sotto).
Area libera Heap Stack Segmento dati Dati di P1 Segmento codice Programma P1
Se il programma contiene dei sottoprogrammi, le variabili globali, cioè quelle dichiarate nel programma principale, vengono associate a una o più celle di memoria in modo statico nel segmento dati, che rimane fisso per tutta la durata dell'esecuzione del programma.
Tuttavia, nell'istante in cui viene attivato un determinato sottoprogramma, verrà allocata nel segmento stack una zona di memoria per le sue variabili, che sarà poi liberata alla fine dell'esecuzione del sottoprogramma stesso (RDA) (vedi figura sotto). II segmento stack, come si nota dal tratteggio riportato nelle varie figure, non ha una dimensione prefissata: può crescere sino a occupare l'intero heap
Area libera Heap Sottoprogramma S2 Stack Sottoprogramma S1 Segmento dati Dati di P1 Segmento codice Programma P1
Analogamente, allocando numerose variabili dinamiche, l'heap può crescere sino a occupare l'intero segmento stack. E evidente che le due aree si contendono lo spazio: occorre evitare che una zona invada l'altra. Per ottenere una buona flessibilità, sia lo stack che l'heap crescono occupando memoria a partire dagli estremi dell'area disponibile, muovendosi in direzioni convergenti: l'eventuale collisione provoca l'interruzione del programma
Heap Variabili dinamiche Stack Sottoprogramma S2 Sottoprogramma S1 Segmento dati Dati di P1 Segmento codice Programma P1
Per allocare lo spazio dedicato in memoria all'ambiente di lavoro di un programma (variabili e strutture dati) si possono scegliere sostanzialmente due strategie:
Con questa ultima tecnica di gestione della memoria, quindi, è possibile allocare nuove variabili quando diviene necessario ed eliminarle quando non sono più utili, il tutto durante l'evoluzione del processo di elaborazione. La deallocazione delle vecchie variabili non più utilizzate (garbage collection) può essere:
Le strutture dati possono essere classificate in:
Abbiamo già visto le principali strutture dati statiche, cioè vettori, matrici e tabelle. Quando è necessario gestire strutture dati che richiedono un elevato numero di inserimenti o di cancellazioni, le strutture statiche possono però risultare ina- deguate. Ciò è dovuto alla loro scarsa flessibilità, che deriva dal fatto che è necessario co- noscere a priori il numero di elementi che le compongono. Inoltre, in una struttura statica, volendo mantenere ordinata la struttura, l'inse- rimento di un nuovo elemento richiede la riscrittura in una posizione più avanti di tutti gli elementi che lo seguono. Analogamente, per eliminare un elemento senza lasciare spazi inutilizzati, biso- gna spostare di una posizione indietro tutti gli elementi che seguono quello can- cellato. Questo è necessario perché le celle di memoria che contengono la strut- tura statica sono contigue.
Per ovviare ai limiti delle strutture dati statiche, occupando effettivamente solo la memoria che di volta in volta è necessaria, si utilizzano le strutture dati dinamiche, come liste, code e pile, per le quali la memoria utilizzata non è necessariamente fisicamente contigua, ma di volta in volta viene al- locato un singolo elemento.
Le variabili dinamiche vengono create al momento del bisogno allocando la memoria necessaria a contenerle all'interno del segmento heap. La parte di memoria centrale destinata al segmento heap ha però una dimensione limitata. Un programmatore potrebbe allocare notevole spazio di memoria per le sue variabili dinamiche all'interno del proprio programma, causando la saturazione dell'heap. Tale situazione viene segnalata dai sistemi operativi attraverso messaggi di memory overflow o out of memory. Per evitare tali situazioni e buona norma di programmazione deallocare le variabili dinamiche quando queste non sono più indispensabili per il proseguo dell'elaborazione. Pensa, ad esempio, a variabili temporanee non più necessarie dopo che hanno terminato il loro compito.
In Java ci sono due aree di memoria che svolgono un ruolo fondamentale: lo stack e l'heap.
Java mette a disposizione un gestore automatico della memoria che si occupa di tutti i compiti legati all'allocazione e deallocazione della memoria. Il codice Java interagisce con questo gestore solo quando usa l'operatore new per creare nuovi oggetti. Il vantaggio di avere un gestore di memoria automatico si traduce in una semplificazione dell'attività di programmazione e nell'eliminazione degli errori di programmazione dovuti alla gestione dei puntatori
Quando un oggetto viene creato, viene allocata nello heap la memoria di cui ha bisogno. Questa memoria varia a seconda del numero di attributi di cui l'oggetto è composto. Mentre l'oggetto viene utilizzato, la memoria resta riservata. Quando un oggetto non è più usato, la memoria deve essere deallocata e resa disponibile per altri oggetti.
In Java la deallocazione è eseguita in modo automatico. Una parte importante dell'interprete Java, infatti, è il Garbage Collector (letteralmente "raccoglitore di spazzatura"): si tratta di un sistema automatico che si occupa di recuperare le parti di memoria inutilizzate per metterle a disposizione del programma. Il Garbage Collector tiene traccia dello stato di tutti gli oggetti: quando si accorge che un certo oggetto non viene più usato, interviene per liberare la memoria occupata e renderla disponibile per usi futuri. Questo modo di gestire la memoria presuppone che il Garbage Collector resti attivo durante tutta l'esecuzione di un'applicazione Java. Il gestore della memoria può stabilire che un oggetto non è più utilizzato contando il numero di riferimenti a quell'oggetto
Gli oggetti non possono essere distrutti esplicitamente dal programmatore o dalla programmatrice: la deallocazione viene fatta in modo automatico dal Garbage Collector. Quello che può fare il programmatore è impostare tutti i riferimenti a un particolare oggetto con il valore null. In questo modo non distrugge l'oggetto, ma lo candida a essere gestito dal Garbage Collector