Heap allocation e garbage collector di Oberon Algoritmo Quick Fit e garbage collector mark and sweep
Introduzione[1] Lallocazione dinamica della memoria è una delle maggiori cause di rallentamento nellesecuzione di un programma Serve un algoritmo in grado di allocare memoria il più velocemente possibile
Introduzione[2] Tenendo conto che il 10% del codice è responsabile al 90% del tempo di esecuzione di un programma É stato sviluppato un algoritmo di allocazione denominato Quick Fit in grado di surclassare i precedenti algoritmi in uso. Con questo algoritmo la maggior parte dei casi di allocazione della memoria è gestita rapidamente
Quick Fit Le idee di base dietro a questo algoritmo sono semplici: In un linguaggio di programmazione ci sono generalmente solo pochi tipi puntatore Le allocazioni più frequenti sono di tipi relativamente piccoli, con un numero fisso di quantità di memoria da allocare (es. record con pochi campi)
Strutture dati dellalgoritmo[1] Lo schema basilare per un algoritmo di tipo Quick Fit prevede la divisione della memoria in due parti logiche: Memoria correntemente allocata o allocata in passato (Working Storage) Memoria che non è mai stata allocata (Tail)
Strutture dati dellalgoritmo[2] Più precisamente il working storage è composto da: Un array di Quick Lists, una per ogni blocco di una certa dimensione (indice), compresa tra minSize e maxSize (dimensioni da scegliere per coprire la maggior parte delle richieste di allocazione del programma). Ogni elemento dellarray può essere o vuoto o contenere un puntatore a una lista di blocchi liberi di grandezza pari al suo indice. Una lista (Misc List) che contiene i blocchi liberi di grandezza o inferiore a minSize o superiore a maxSize
Schema dellalgoritmo[1] Quando il programma effettua la richiesta di un blocco di dimensione compresa tra minSize e maxSize e la quick list relativa non è vuota viene tolto il primo blocco libero dalla lista e il suo indirizzo è passato al programma Se la richiesta può essere assolta usando tail senza estendere lo spazio degli indirizzi, al programma viene passato lindirizzo di tail e linizio di tail viene spostato in avanti della grandezza richiesta Altrimenti viene usata una tecnica molto più complicata che non vedremo
Schema dellalgoritmo[2] La deallocazione è ancora più semplice Se la grandezza della memoria da deallocare è coperta da una Quick List, la memoria viene linkata ad essa Altrimenti viene messa nella Misc List
Osservazioni Nella maggior parte dei casi lallocazione consiste in un confronto, nel trovare la quick list corrispondente, vedere se la quick list corrispondente non è vuota e in un delinking. Quando una quick list è vuota viene allocato spazio da tail, solo raramente è necessaria una strategia più complicata e inefficiente Con lalgoritmo Quick Fit abbiamo una allocazione/deallocazione di blocchi di memoria che probabilmente saranno riutilizzati
Garbage collection Il garbage collector di Oberon
Introduzione[1] La deallocazione deve essere fatta dal programmatore prima che le variabili puntatore siano irrangiungibili In caso di mancata deallocazione si creano le cosiddette dangling reference o dangling pointer e cioè resta della memoria nello heap che non è più utilizzabile dallalgoritmo di allocazione
Introduzione[2] È quindi necessaria la presenza di un oggetto in grado di trovare queste aree di memoria e liberarle Questoggetto si chiama garbage collector Deve inoltre occupare ed utilizzare la minor quantità di memoria possibile, poiché deve essere attivato quando essa sta per finire
Garbage collector[1] In Oberon ne è stato implementato uno di tipo mark-and-sweep Lavora in due fasi: Nella prima (mark) vengono marcati tutti gli oggetti che sono raggiungibili dal programma attraverso i puntatori Nella seconda tutti gli oggetti non marcati vengono dichiarati liberi
Garbage collector[2] Nella prima fase il g.c. deve poter riuscire a raggiungere tutti i puntatori che sono utilizzati nel programma È necessario, quindi, che ogni record abbia un puntatore (ad es. di nome tag) ad un record nascosto che conterrà un campo size (la grandezza del record) e un campo ptable (array) composto dagli offset che descrivono la posizione dei puntatori allinterno del record Questa struttura dati viene chiamata type descriptor
Fase di mark Si usa un procedura che prende in input un indirizzo Da questo indirizzo utilizzando il type descriptor si risale a tutti i suoi puntatori (in modo ricorsivo). In realtà per minimizzare luso di memoria viene utilizzato uno pseudo-stack Viene tenuta una variabile come stack pointer che punta alloggetto che contiene il predecessore corrente e il predecessore di ogni record viene memorizzato in un campo puntatore del record stesso Tutti i puntatori raggiunti vengono marcati
Fase di sweep Innanzitutto tutte le Quick List e la Misc List vengono svuotate Lintero heap è attraversato sequenzialmente. Se un blocco di memoria era stato marcato nella fase precedente viene semplicemente smarcato Se un blocco non era stato marcato nella fase precedente allora viene inserito nella corrispondente Quick List (Small Blocks) o nella Misc List (Large Blocks) a seconda delle sue dimensioni. Se ci sono blocchi liberi consecutivi vengono considerati come un blocco unico
Bibliografia Quick Fit: An Efficient Algorithm for Heap Storage Allocation – Charles B. Weinstock, William A. Wulf An Integrated Heap Allocator/Garbage Collector – Beat Heeb, Cuno Pfister