Resúmenes

Apuntes universitarios en formato Markdown desde Obsidian.

Gestione della memoria

download Descargar MD

Gestione della memoria virtuale

Ogni processo come abbiamo già detto non può andare ad intaccare la porzione di memoria di un altro processo pertanto avviene un processo di virtualizzazione della RAM che permette di isolare i vari processi. Per comprendere meglio la gestione di quest'ultima facciamo riferimento, con un linguaggio simil C++, alle seguenti supposizioni:

  • spazio degli indirizzi reali: ad esempio,
    virtualByte mem[M];

    dove M sta ad indicare la memoria RAM che il computer possiede e può contenere 512MB, 1GB, ..., 16 * 2^30 - 1 bit. Può essere diviso in pagine nel seguente modo:

    byte P[X][4096]

    dove X dipende dalla memoria e 4096 sta ad indicare i KB della pagina (ogni pagina contiene 4096KB);

  • spazio degli indirizzi virtuali: ad esempio,
    virtualByte memPn[N];

    dove N è la grandezza dei registri (quindi in architetture a 64bit, significa che ci sono registri fino a 2^64) e può contenere 4GB per gli Intel x32. Può essere diviso in pagine nel seguente modo:

    byte Pn[1MB][4096]

Ogni processo quindi viene illuso di avere 4GB ma in realtà tutti gli indirizzi che possiede sono "virtuali". Pertanto viene applicato un meccanismo di conversione da indirizzo virtuale ad indirizzo fisico: nel dettaglio andiamo ad introdurre una tabella delle Page Entries ed una per ogni processo. Un esempio d'implementazione è il seguente:

typedef pagina byte[4096];
pagina P[X];

class PageEntry {
    bool inMemoria;
    bool acceduto;
    bool scritto;
    long posizione;
    long posizioneSuDisco;
    bool leggibile;
    bool scrivibile;
    bool eseguibile;
}

class process {
    ....
    PageEntry pageDirectory[1MB];
    virtualByte mem(4GB, pageDirectory);
}

Attenzione, X dipende dalla memoria RAM reale e P[X] è un array che non è tutto materializzato all'interno nella RAM ma bensì è smistato nella memoria di massa.

Ad ogni processo viene assegnata una tabella detta Page Entries che tiene conto se una determinata pagina è in RAM, ed eventualmente dove, oppure sul disco. Possiamo vederlo come un array di 1MB che tiene conto dello stato di ogni pagina caricata su quel processo.

Esiste inoltre un cosiddetto file di SWAP che non è altro che un punto di appoggio in cui vengono memorizzate porzioni di RAM (il long posizione fa riferimento a questo file).

byte& virtualByte::operator[] (long indirizzo) {
    pagina = indirizzo >> 12;
    offset = indirizzo % 4096;
    PageEntry pe = pageDirectory[pagina];
    if (!pe.inMemoria) {
        // page fault.
        pe.posizione = trovaPaginaLibera();
        loadPage(pe.posizioneSuDisco); // swap in
        pe.scritto = false; // pagina fresca presa da disco
    }
    pe.acceduto = true;
    if (operazione di Scrittura)
         pe.scritto = true;
    return P[pe.posizione][offset];
}

Facendo riferimento a quest'ultimo codice, possiamo vedere che se una pagina PE non è in memoria RAM (page fault → non è nel cosidetto working set), il sistema operativo deve procedere con un operazione di Swap in che consiste nell'andare in memoria (grazie alla variabile long posizioneSuDisco) prendere un blocco di pagine e caricarlo in RAM. Il processo inverso è lo Swap out che permette di ripulire da pagine non attualmente utilizzate la RAM.

Swap in e Swap out

Ci sono dei thread ad altissima priorità che si occupano di caricare in anticipo le pagine che si prevede siano usate (Swap in) e di eliminare le pagine non usate (Swap out).

Swap out nel dettaglio

È un semplice algoritmo i cui le pagine stanno in una lista FIFO. Quando una pagina p è acceduta, viene settato il bit p.acceduto a 1, e viene messa in testa alla FIFO.

Un thread pulitore elimina periodicamente, dalla fine della coda (swap out), quelle pagine p in cui trova p.acceduto == 0 e pone p.acceduto = 0 per tutte le altre pagine. Le pagine accedute periodicamente tendono ad evitare di essere "swapped out".

Il pulitore è tanto più aggressivo tanto più c'è meno memoria. Un esempio di codice di swap out è il seguente:

void swapout(PageEntry p) {
    if (p.scritto)
        p.posizioneSuDisco = scriviSuDisco(p.posizione);
    p.inMemoria = false;
}

Trashing

Una macchina performante deve possedere abbastanza RAM, il rischio che si corre è quello del trashing. Il processore è perennemente in uso per ricercare pagine che vengono costantemente eliminate dalla RAM (swap out).

Protezione

Generalmente i processi hanno due porzioni di RAM: User Space e System Space (c'è il codice del sistema operativo e la cosiddetta Memoria Shared).

È fisicamente impossibile che un processo acceda alla memoria di un altro. Tuttavia i processi condividono tutti lo stesso System Space. Pertanto si può sfruttare quest'ultimo per poter condividere porzioni di RAM fisica tra più processi partendo da indirizzi virtuali differenti (si sfruttano le page entries).

Mobile OSes

Nei sistemi operativi dei dispositivi mobili viene utilizzato Linux per diverse ragioni:

  • scheduler efficiente;
  • kernel semplice ed intuitivo;
  • non offre meccanismi di swap out ma viene usato il modulo OOM Manager (Out of Memory Manager) attraverso cui un processo viene killato per poter liberare memoria indipendentemente se questa si stia utilizzando o meno.

VMMAP

Possiamo distinguere tre diverse barre: commited (memoria effettivamente impegnata dal processo), private bytes e working set (la parte di Memoria RAM che è realmente utilizzata nel computer. La differenza tra committed e working set risiede all'interno del disco).

Ogni barra si caratterizza di diverse partizioni tra cui possiamo distinguere:

  • Image: rappresenta il file .EXE;
  • Mapped File: un file che generalmente risiede nel disco viene mappato nella ram per velocizzare il processo di acquisizione;
  • Shareable: codice che viene ripetuto in più processi e quindi condiviso;
  • Heap: rappresenta l'esito di tutte le "new" effettuate;
  • Managed Heap;
  • Stack: porzione che viene utilizzata per allocare le variabili locali;
  • Private data: dati che non devono essere condivisi dagli altri processi;
  • Page Table;