In informatica, la gestione della memoria è una forma di gestione delle risorse relativa alla memoria dei computer. Lo scopo principale è quello di orchestrare l'allocazione di porzioni della memoria di sistema ai vari programmi che la richiedono. La gestione della memoria è un aspetto critico di ogni sistema di elaborazione che supporta l'esecuzione di più processi contemporaneamente.
Gerarchie di memoria La grande quantità di dati normalmente presente in un elaboratore è memorizzata su supporti che possono presentare caratteristiche molto diverse tra loro, in termini di tempo di accesso, di capacità e di costo. Tali supporti sono organizzati come una struttura gerarchica in cui al livello più alto troviamo i dispositivi di memoria più lenti, con capacità maggiore e meno costosi; man mano che si scende in questa gerarchia, i supporti hanno capacità sempre più piccola, tempo di accesso sempre più basso e costo maggiore. L'obiettivo che si vuole raggiungere è quello di ottimizzare il rapporto prestazioni/costo, ottenendo, così, prestazioni equiparabili al caso in cui tutte le informazioni necessarie siano disponibili al livello più basso della gerarchia, con un costo paragonabile al caso in cui siano concentrate al livello più alto.
In un elaboratore comune una tipica gerarchia di memoria è quella in cui si trova, al livello più alto, il disco fisso, dove le informazioni vengono conservate in maniera permanente; subito dopo si trova la memoria principale (DRAM/SDRAM), di elevata capacità nell'ordine del GB, basso costo e basso tempo di accesso. Qui vengono conservate le informazioni relative ai processi in esecuzione: quando un nuovo processo viene caricato, vi verranno trasferite almeno le informazioni basilari che ne permetteranno la messa in esecuzione. Nel caso tale livello della gerarchia risultasse saturo, verranno adottate politiche di ottimizzazione che possono consistere dalla compattazione della memoria allo swap-outAzione eseguita dal gestore della memoria quando un processo o un'area della memoria virtuale di esso viene scelta per essere spostata nella swap-area. Tale azione consiste nella copia della memoria virtuale o di un'area di essa, se vengono adottate tecniche di segmentazione o paginazione a domanda, dalla memoria principale alla swap-area. delle pagine, il quale consiste nel trasferimento di informazioni al livello superiore, ossia al disco fisso.
Ai livelli inferiori abbiamo la memoria cache; possono esistere più livelli di questo tipo di memoria e vengono normalmente indicati con una serie decrescente di numeri, via via che si scende nella gerarchia. Normalmente il livello cache L1 è “on-chip”, ossia è direttamente presente nella CPU in maniera tale da ridurre fisicamente la latenza dei collegamenti. Il livello più basso della gerarchia è sicuramente rappresentato dai registri del processoreCostituiscono un'estensione della memoria disponibile al programma in esecuzione. Sono implementati direttamente al livello firmware, nella parte operativa del processore e sono quindi caratterizzati da un tempo di accesso molto basso. Normalmente sono organizzati in una (piccola) memoria di registri e vengono riferiti mediante indirizzamento assoluto. il cui tempo di accesso è valutabile in un ciclo di clockInteravallo di tempo necessario (in nanosecondi) affinché sia la parte operativa che la parte controllo di un'unità di elaborazione si stabilizzino. Ogni ciclo di clock i valori che sono in ingresso ai registri dell'unità diventano i valori dello stato corrente e quindi i valore di uscita..
Tecniche di gestione della memoria Un meccanismo di gestione della memoria può essere individuato da quattro parametri fondamentali, quali:
rilocazione: statica o dinamica spazio virtuale: unico o segmentato allocazione della memoria fisica: contigua o non contigua caricamento dello spazio virtuale: tutto insieme oppure a domanda.
Fatta eccezione per alcune, ad ogni combinazione di questi quattro fattori corrisponde una tecnica di gestione della memoria.
Rilocazione Gli indirizzi generati dal processore su cui è in esecuzione un processo sono detti “indirizzi logici” o “virtuali” e fanno riferimento alla memoria virtuale del processo stesso. Tali indirizzi, però, non corrispondono necessariamente agli indirizzi dove sono effettivamente rese disponibili le informazioni cercate, ossia gli “indirizzi fisici”, per questo motivo è necessario che sia messo in atto un meccanismo che consenta di mettere in corrispondenza gli indirizzi logici con gli indirizzi fisici: la rilocazione statica prevede, appunto, che all'atto del caricamento del processo, il “caricatore”, che a questo punto conosce l'area di memoria fisica dove verrà caricata la memoria virtuale dello stesso, provveda a sostituire tutti gli indirizzi logici che possono essere generati, negli indirizzi fisici corrispondenti.
Questa politica, se da un lato permette di risparmiare l'eventuale overhead dovuto alla traduzione a runtime degli indirizzi logici, tempo che peraltro verrà speso all'atto del caricamento, dall'altro non è prestante in caso vengano adottate politiche di swapping, in quanto, ogni qual volta verrà fatto lo swap-inAzione eseguita dal gestore della memoria quando viene generato un indirizzo virtuale facente riferimento ad un'area di memoria virtuale di un processo residente nella swap-area. Tale azione consiste nello spostare la memoria virtuale del processo, o eventualmente il segmento o la pagina, se vengono adottati schemi di segmentazione o paginazione a domanda, dalla swap-area nella memoria principale. di un'area di memoria precedentemente scaricata, potrebbe rendersi necessario effettuare nuovamente la rilocazione di tutti gli indirizzi.
Spazio virtuale La memoria virtuale di un processo in cui sono presenti tutte le informazioni necessarie alla sua esecuzione, come il codice, l'area riservata per lo stack e i dati, può essere strutturata come uno spazio degli indirizzi contiguo, ossia con indirizzi da 0 a N, in cui N rappresenta la dimensione della memoria virtuale, oppure può essere suddivisa in segmenti indipendenti, ad esempio un segmento per il codice, un segmento per lo stack ed infine uno per i dati. Nel secondo caso risulta più naturale il concetto di poter applicare diversi permessi di lettura/scrittura ad ogni segmento.
Allocazione della memoria fisica Definisce come deve essere scelto lo spazio di memoria fisica da assegnare al processo. Supponendo di essere nel caso di spazio virtuale unico, nel momento in cui questo deve essere caricato in memoria, occorre individuare un'area libera di dimensioni maggiori o uguali a N, dove N rappresenta la dimensione dello spazio degli indirizzi; se, per ipotesi, fossero disponibili diverse aree di dimensioni minori di N, queste non sarebbero selezionabili anche se la somma delle loro dimensioni fosse maggiore o uguale a N.
Nel caso di spazio virtuale segmentato il problema è riconducibile a quello prima descritto, in quanto il fenomeno ora non si verificherebbe al livello dell'intero spazio degli indirizzi, ma del singolo segmento, anche se in questo modo aumentano le probabilità di trovare una partizione di dimensione sufficiente, essendo la dimensione del singolo segmento minore rispetto a quello dell'intera memoria virtuale.
Il fenomeno appena descritto è definito “frammentazione” e rappresenta un problema di ottimizzazione della gestione della memoria in quanto tende a ridurre l'utilizzazione della stessa. Nei sistemi con rilocazione dinamica il problema della frammentazione può essere risolto con il compattamento della memoria. In questi sistemi, infatti, viene adottata una funzione, detta funzione di rilocazione, che permette di far corrispondere ad ogni indirizzo virtuale l'indirizzo fisico corrispondente; sfruttando questa caratteristica, se venisse richiesta un'area di memoria contigua di dimensione N, ma la memoria risultasse frammentata, le aree libere potrebbero essere compattate in un'unica area di dimensione pari alla somma delle precedenti. Tale modifica non si ripercuoterà sull'esecuzione degli altri processi quando la funzione di rilocazione viene aggiornata al nuovo stato della memoria. Nel caso di rilocazione statica, l'allocazione della memoria fisica deve essere forzatamente contigua; infatti, in questo caso gli indirizzi sono tradotti a tempo di caricamento e ne consegue che ad indirizzi virtuali contigui debbano corrispondere indirizzi fisici contigui.
Un chiaro esempio di come non possa essere altrimenti lo si può avere pensando al ciclo fetch-executeIl programma eseguito dal processore per tutto il suo periodo di attività. Le fasi di tale attività consistono fondamentalmente nel recupero della prossima istruzione da eseguire: l'esecuzione di questa, l'incremento del contatore "istruzioni", il trattamento di eventuali eccezioni e il trattamento di eventuali interruzioni. del processore, il quale cercherà la prossima istruzione da eseguire all'indirizzo virtuale successivo rispetto a quello dell'istruzione la cui esecuzione si è appena conclusa; se la memoria virtuale non fosse allocata in maniera contigua è evidente che tale modello fallirebbe.
Caricamento dello spazio virtuale Indica se lo spazio virtuale deve essere caricato in memoria per intero, copiandolo dal disco alla memoria principale, oppure se ne deve essere caricata solo una parte, eventualmente anche minima, come solo il descrittore di processo. In quest'ultimo caso, quando viene generato un indirizzo logico che fa riferimento ad un'area di memoria virtuale non ancora presente in memoria principale, viene sollevata un'eccezione chiamata page fault, la cui gestione porterà alla copia di quest'ultima in memoria principale.
Partizioni Partizioni fisse o variabili Tale tecnica non utilizza meccanismi hardware di supporto alla gestione della memoria (MMU), effettuando la rilocazione statica degli indirizzi virtuali mediante il caricatore rilocante. L'allocazione della memoria fisica viene fatta in maniera continua, lo spazio virtuale è unico e viene caricato tutto insieme. La memoria è suddivisa in N partizioni fisse, ovvero di indirizzo iniziale e dimensioni determinate, di cui una è riservata al sistema operativo mentre le altre sono disponibili ad ospitare lo spazio virtuale dei processi.
Quando un processo viene mandato in esecuzione, se vi sono partizioni libere verrà scelta la partizione di dimensione minima tra quelle la cui dimensione è maggiore o uguale alla dimensione dello spazio virtuale del processo stesso; se non esiste una partizione con queste caratteristiche, oppure tutte le partizioni sono occupate, si provvede ad effettuare lo swap-out dello spazio virtuale di un processo, con il vincolo che quando questo dovrà tornare in esecuzione, lo swap-in dovrà essere fatto nella stessa partizione dove prima risiedeva. Tale vincolo è da imputare all'adozione della rilocazione statica. È evidente che la probabilità di trovare partizioni con la stessa dimensione dello spazio virtuale del processo che di volta in volta viene caricato è piuttosto bassa, ne consegue che la differenza tra la dimensione della partizione selezionata e la dimensione della memoria virtuale costituisce un'area di memoria non utilizzata.