La gerarchia delle memorie Gestione della memoria Ogni processo

Transcript

La gerarchia delle memorie Gestione della memoria Ogni processo
La gerarchia delle memorie
Gestione della memoria
Ogni processo, per avanzare necessità che il relativo programma risieda
nella memoria centrale, Tale programma è costituito da memoria e dati.
Lo spazio fisico è l'insieme degli indirizzi accessibili fisicamente e
costituisce la memoria fisica; lo spazio logico è uno spazio astratto di
indirizzi logici (l'indirizzo logico della prima istruzione sarà 0), ma durante
l'esecuzione gli indirizzi devono essere fisici (l'indirizzo fisico della prima
istruzione sarà l'indirizzo della locazione di memoria a partire dalla quale
è stato caricato il programma).
Occorre pertanto, al fine di eseguire il programma trasformare gli indirizzi
logici in indirizzi fisici. Questa traduzione è detta Mapping o Rilocazione
degli indirizzi e viene svolta dalla MMU.
Registri e Cache
I registri rappresentano una piccola parte di memoria utilizzata per
velocizzare l'esecuzione dei programmi fornendo un accesso rapido ai
valori usati più frequentemente — tipicamente, i valori correntemente in
uso in una determinata parte di un calcolo.
La Cache è una memoria particolarmente veloce ed ha il compito di
tenere le parole di memoria più usate, si incrementa così notevolmente
la velocità di risposta della macchina. Viene utilizzata quindi una
memoria statica di dimensioni molto limitate (perché estremamente
costosa) ma con tempi di accesso molto ridotti (fino all’ordine di un solo
ciclo di clock) per contenere le parole di memoria usate più di frequente
e quando la CPU richiede una certa parola prima di andarla a ricercare in
memoria centrale si verifica se essa è presente nella cache. Si distinguono
i diversi livelli di cache per aumentare ancora di più la scalabilità:
 L1: cache interna al processore, solitamente sincrona con il
processore, spesso distinta per dati e istruzioni (split cache)
 L2: generalmente unificata per dati e istruzioni, può essere interna
o esterna
 L3: generalmente unificata per dati e istruzioni, può essere o meno
presente ed è interna o esterna
Il principio tramite il quale si sceglie cosa mettere in cache è noto col
nome di “principio di località” che asserisce che se viene indirizzata una
parola, supponiamo all’indirizzo di memoria A, è molto probabile che le
successive e precedenti richieste (in ordine cronologico) siano riferite a
locazioni di memoria vicine ad A
Per la gestione della memoria esistono diverse tecniche:
La rilocazione
Nel momento in cui il processo deve essere eseguito allora è necessario
caricarlo in memoria fisica. Tutti gli indirizzi virtuali del processo devono
essere rilocati in memoria fisica. Rilocare un processo significa tradurre
tutti gli indirizzi virtuali di quel processo nei corrispondenti indirizzi fisici
tramite una funzione di rilocazione. Esistono due tecniche per fare ciò:
rilocazione statica e rilocazione dinamica. Nel caso di rilocazione statica
è il loader, che prende anche il nome di caricatore rilocante, che prima di
caricare il programma in memoria traduce tutti gli indirizzi virtuali in
indirizzi fisici. Nel caso di rilocazione dinamica è invece un dispositivo
hardware, la MMU, residente nello stesso chip del processore, che
effettua la traduzione degli indirizzi logici in indirizzi fisici durante
l’esecuzione del processo ovvero run time. La memoria virtuale di un
processo parte dall’indirizzo 0 mentre in memoria fisica in generale il
caricamento avviene a partire da un indirizzo I diverso da zero.
Partizioni fisse
La memoria è divisa, al momento dell'installazione
del SO in partizioni di dimensione fissa, non
necessariamente uguali, ciascuna delle quali potrà
contenere un intero programma. Il SO, per la
gestione farà uso della tabella delle partizioni di
tante righe quante sono le partizioni in memoria,
ed ognuna conterrà per ogni partizione, indirizzo
iniziale, indirizzo finale, PID del programma che la
occupa (0 se la partizione è libera).
La rilocazione è statica gli indirizzi vengono quindi
trasformati da logici a fisici al momento del caricamento in memoria del
programma.
Il grado di multiprogrammazione è fisso in quanto si può caricare un solo
programma per partizione. Facendo uso della partizione fissa si avrà il
problema della frammentazione interna in quanto la locazione deve
essere più grande del programma caricato su essa.
Contigua singola
La memoria è divisa in due parti, una riservata al
sistema operativo ed un'altra ai programmi utente.
Il programma sarà sempre caricato in memoria
centrale a partire dallo stesso indirizzo fisico. Dal
momento che è possibile caricare un solo
programma alla volta in memoria, è impossibile fare
uso della multiprogrammazione.
La rilocazione è assoluta, in quanto come si evince
anche da quanto detto sopra, gli indirizzi nei quali
verrà immagazzinato il programma sono sempre gli stessi, pertanto gli
indirizzi vengono trasformati da logici a fisici al momento della creazione
del programma eseguibile.
Partizioni variabili
Le partizioni vengono create dinamicamente in base alle richieste.
Inizialmente si hanno due partizioni una per il SO e una, che rappresenta
tutto il resto della memoria libera, dedicata ai programmi utente.
Quando è necessario allocare programmi in memoria, essi vengono
inseriti in maniera sequenziale. Quando un programma termina la sua
esecuzione libera la memoria e la sua partizione, se vi sono partizioni
libere adiacente si procede con la compattazione in un’unica partizione
più grande. Cosi procedendo però si andrà in contro a frammentazione
esterna poiché lo spazio non allocato non fa parte di una partizione usata
da un programma, come invece avviene con la frammentazione interna.
Il SO per la gestione della memoria farà uso di una tabella delle partizioni,
che contiene l’indirizzo di base nella memoria fisica, simile a quella della
partizione fissa con la differenza che il numero di righe stavolta sarà
variabile, poiché abbiamo un numero variabile di partizioni. La scelta
della partizione libera da utilizzare può essere fatta con diverse strategie:
 First fit: viene scelta la prima partizione sufficiente a contenere il
programma; favorisce il formarsi di una grande partizione libera
(verso il fondo della memoria)
 Best fit: viene scelta la più piccola partizione sufficiente a contenere
il programma, così da non frammentare inutilmente le grosse
partizioni
 Worst fit: viene scelta la più grande partizione che può contenere il
programma
La rilocazione può anche essere statica, ma in genere è dinamica: il
programma viene caricato in memoria senza alcuna trasformazione di
indirizzi, che vengono trasformati al momento dell'esecuzione. L'indirizzo
iniziale della partizione viene posto in uno speciale registro base e
durante l'esecuzione l'indirizzo fisico viene calcolato sommando
all'indirizzo logico il contenuto del registro base. In presenza di
rilocazione dinamica, per eliminare la frammentazione, è possibile
effettuare il compattamento delle partizioni occupate in modo da creare
un’unica grande partizione libera, risultato della somma di tutti i
frammenti liberi, operazione questa però abbastanza costosa in termini
di overhead.
Segmentazione
Le tecniche di gestione della memoria fin qui illustrate prevedono che
ogni programma sia logicamente lineare e venga caricato in un'area
contigua di memoria. Con la segmentazione questo vincolo cade, in
quanto ogni programma viene suddiviso in più segmenti, ciascuno dei
quali potrà essere successivamente caricato in una diversa partizione. In
ogni segmento gli indirizzo logici partono da 0; il campo indirizzo delle
istruzione è formato numero del segmento (indirizzo segmento 1 byte) e
displacment (indirizzo all'interno del segmento 2 byte). La memoria
centrale viene gestita a partizioni variabili, con l'ausilio della tabella delle
partizioni, contenente, per ogni partizione, indirizzo iniziale, indirizzo
finale, PID e numero del segmento del programma che la occupa (0 se
libera). La rilocazione è dinamica e per risolvere gli indirizzi per ogni
programma si usa una tabella dei segmenti (di tante righe quanti sono i
segmenti del programma e avente, per ogni segmento, l'indirizzo della
partizione nella quale è stato caricato il relativo segmento del
programma) il cui indirizzo è contenuto nel registro base.
Paginazione
La segmentazione ridimensiona il problema della frammentazione, ma
non lo elimina. La tecnica della paginazione è simile a quella della
segmentazione, con la differenza che le pagine sono di lunghezza
fissa(1kb, 2kb, 4kb).
Il programma viene, suddiviso in pagine a lunghezza fissa dal compilatore.
La memoria centrale viene suddivisa in pagine di uguale dimensione
adatte a contenere porzioni di programma di eguale misura. Le pagine
del programma possono essere caricate ovunque nella memoria
pertanto la memoria viene sfruttata al 100%(in po' di spreco si ha
soltanto nell'ultima pagina).
Il campo indirizzi delle istruzioni, come per la segmentazione è formato
da numero pagina e displacement (indirizzo all'interno della pagina).
Il sistema operativo gestisce la memoria per mezzo della tabella di
occupazione pagine, di tante righe quante sono le pagine, contenente,
per ogni riga l'indicazione di chi occupa la pagina corrispondente (PID e
numero pagina del processo che la occupa o 0 se è libera).
La rilocazione è dinamica e per risolvere gli indirizzi, per ogni programma
si usa una tabella delle pagine, il cui indirizzo è contenuto nel registro
base.
MMU e TLB
L'unità di gestione della memoria, o memory management unit,
in sigla MMU, è una classe di componenti hardware che gestisce le
richieste di accesso alla memoria generate dalla CPU.
La MMU può avere vari compiti tra cui la traslazione (o traduzione) degli
indirizzi virtuali in indirizzi fisici (necessaria per la gestione della
memoria), la protezione della memoria, il controllo della cache della CPU.
La MMU contiene una tabella delle pagine indicizzata dal numero della
pagina. Ogni elemento di questa tabella (detto PTE o Page Table Entry)
restituisce il numero fisico della pagina corrispondente a quello virtuale,
che, combinato con l'offset della pagina, forma l'indirizzo fisico completo.
Il Translation Lookaside Buffer (TLB) è un buffer, cioè una memoria
tampone che l'MMU (Memory Management Unit) usa per velocizzare la
traduzione degli Indirizzi Virtuali. Il TLB possiede un numero fisso di
elementi della Page Table, la quale viene usata per mappare gli Indirizzi
Virtuali in Indirizzi Fisici.
Segmentazione paginata
Questa tecnica prevede sia la segmentazione che la paginazione: i
programma sono suddivisi in segmenti che, a loro volta, sono suddivisi in
pagine e la memoria centrale è suddivisa in pagine. Il campo indirizzo
delle istruzioni è composto da numero segmento, numero pagina e
displacement.
Per ogni programma c'è una tabella dei segmenti, puntata dal registro
base, ogni riga della quale punta alla tabella delle pagine del relativo
segmento.
Il page fault
Quando una pagina richiesta non è ancora stata caricata in memoria
allora si verifica un page fault. Il page fault viene gestito dal sistema
operativo che provvede a caricare da disco in memoria la pagina richiesta.
Il processo che ha provocato il page fault viene sospeso e il suo contesto
salvato nel suo descrittore. Il sistema operativo prima di caricare la
pagina richiesta controlla se in memoria fisica c'è un frame libero. Se non
c'è alcun frame libero allora viene cercata una pagina da rimpiazzare. Il
rimpiazzamento avviene usando un opportuno algoritmo (Ad esempio
FIFO)
Caricamento dinamico e Memoria virtuale
Con le precedenti tecniche di gestione della memoria i processi in
esecuzione devono essere caricati completamente in memoria. Il
caricamento dinamico, invece, consente che un processo sia
parzialmente presente in memoria centrale e che le sue parti siano
caricate e scaricate dalla memoria secondaria quando serve.
Ad ogni processo è assegnata un'area di memoria centrale (che lo
contiene parzialmente) ed un'area su disco, area di swap, che contiene la
sua immagine, istruzione e dati, e viene aggiornata durante l'esecuzione.
I processi, oltre alla memoria centrale, usano anche l'area di swap su
disco, usano cioè una memoria virtuale più grande della memoria fisica
centrale. Il loro spazio indirizzabile, indirizzi logici, può essere maggiore
dello spazio fisico della memoria centrale e possono essere eseguiti
contemporaneamente tanti processi dei quali è presente in memoria solo
una piccola parte. A fronte di questo indubbio vantaggio, occorre pagare
un prezzo: lo swapping – carico e scarico (swap in swap out) di processi
da/su area di swap – rallenta l'esecuzione del processo (il tempo di
accesso alla ram è dell'ordine dei nanosecondi mentre quello del disco è
dell'ordine dei millisecondi).
Paginazione dinamica
Questa tecnica permette di eseguire un programma anche se non tutte
le sue pagine sono presenti in memoria; le altre pagine restano nell'area
di swap e vengono caricate all'occorrenza.
Quando il programma fa riferimento ad una pagina non presente in
memoria (page fault) il sistema provvede a caricarla (page swapping) e il
processo viene bloccato finché la pagina non è stata caricata.
La nuova pagina sarà caricata su una pagina libera, se è presente, o su
una occupata; in tal caso potrebbe prima essere necessario salvare la
pagina da sovrascrivere su disco.
La scelta della pagina da sovrascrivere, quando tutte le pagine sono
occupate, si procedete con la sostituzione utilizzando ad esempio, il
seguente algoritmo.
Algoritmo LRU
L'algoritmo di sostituzione utilizzato di solito è LRU(Least recently used)
che si basa sul principio di località globale se una pagina è stata usata di
recente vuol dire che probabilmente verrà riutilizzata a breve. Quindi,
quando occorre sovrascrivere una pagina, si sceglie una pagina non usata
di recente.
Paginazione su richiesta
Le pagine virtuali di un processo non sono caricate tutte insieme ma
vengono caricate solo quando richieste. Se la pagina virtuale richiesta
non è presente in memoria viene generato un page fault che viene
gestito dal sistema operativo come spiegato nei paragrafi precedenti.