Lezione 26 Gestione memoria processi - WEB Lab

Pagina creata da Tommaso Cavalli
 
CONTINUA A LEGGERE
Lezione 26 Gestione memoria processi - WEB Lab
Lezione 26
Gestione memoria processi
Sistemi Operativi (9 CFU), CdL Informatica, A. A. 2020/2021
Dipartimento di Scienze Fisiche, Informatiche e Matematiche
Università di Modena e Reggio Emilia
http://weblab.ing.unimo.it/people/andreolini/didattica/sistemi-operativi
                                                                           1
Quote of the day
                    (Meditate, gente, meditate ...)
“The name was borrowed from
optics, recalls the virtual images
formed in mirror and lenses –
images that are not there but
behave as if they are.”
Peter J. Denning (1942-)
Informatico teorico
Coautore di MULTICS
Coinventore del demand paging
                                                      2
Inventore del concetto di “working set”
INTRODUZIONE

               3
Riassunto delle puntate precedenti
                 (Per schiarirsi un po' le idee)
I meccanismi di gestione della memoria risultati
finora vincenti sono i seguenti.
   Modello di memoria flat (no segmentazione).
   Spazio di indirizzamento di un processo partizionato
   dinamicamente.
   Allocazione dinamica della memoria ai processi.
   Separazione degli spazi degli indirizzi kernel e user.
   Paginazione della memoria.
   Associazione ritardata delle pagine ai frame fisici.
Su questi meccanismi si vuole implementare un
gestore della memoria per i processi utente. 4
Problema: allocazione completa
               (Enormemente inefficiente)

Sembrerebbe naturale:
  caricare completamente in memoria centrale un
  programma appena lanciato.
  fornire subito tutta la memoria richiesta.
Così facendo, però, la memoria principale si
esaurisce molto presto.
Se la memoria principale finisce, le applicazioni
non possono partire.
→ Il grado di multiprogrammazione diminuisce.
                                                5
Un esempio: LibreOffice
                   (Il classico “mastodonte”)
Si consideri, ad esempio, il caricamento completo
di una applicazione grande come LibreOffice.
Si trasferisce in memoria centrale un quantitativo
di dati impressionante.
  Per avere un'idea: pmap $(pgrep soffice.bin)
  e si sommino i valori della seconda colonna.
  In alternativa: eseguire lo script di shell (in allegato)
  lo-memsize.sh.
  Il valore risultante è il quantitativo di memoria in KB
  richiesto per caricare completamente in memoria
  LibreOffice.                                            6
Una domanda esistenziale
             (Ma serve veramente tutta quella roba?)

Serve veramente tutto e subito quel quantitativo
di dati?
  Tutto il codice di Libreoffice è eseguito subito?
  Tutti i font sono usati subito?
  Tutte le funzioni dei menu sono invocate subito?
O è stata fatta una gran fatica (e consumata tanta
memoria) per niente?
                                                       7
Un altro esempio: allocazioni grandi
         (Programmi di calcolo, macchine virtuali, videogiochi)

Sempre più spesso le applicazioni prenotano la
memoria in blocchi grandi.
  Ad esempio, per una macchina virtuale, 2GB.
Domande.
  Tutta quella memoria è usata subito o a breve?
  Che fare se l'allocazione eccede la memoria
  fisica a disposizione? Si ammazza il processo? Lo si
  blocca?
                                                                  8
Una riflessione: il caricamento pigro
            (Si carica solo ciò che serve per l'esecuzione)

IDEA: invece di allocare tutto e subito, il kernel
  associa aree di indirizzi lineari alle diverse componenti
  di una applicazione (codice programma, dati
  programma, codice librerie, dati librerie, stack).
  associa i file relativi su disco a tali aree, se necessario
  (codice → soffice.bin, libreria → libc.so.6, …).
  Carica in memoria “solo il pezzo che serve” (traccia di
  codice o libreria, dato, …).
→Caricamento pigro (lazy). Si caricano in
memoria centrale solo le pagine riferite dalla CPU.
                                                              9
È possibile implementarlo?
              (In maniera efficiente, ovviamente?)

Come si può implementare in maniera efficiente il
caricamento pigro?
Si usano i meccanismi hardware (Intel) descritti
nella lezione precedente.
  Bit delle PTE: contengono lo stato di validità delle
  pagine.
  Page fault: rende valide le associazioni pagina ↔
  frame.
                                                     10
Ma funziona veramente?
                    (Funziona, funziona!)

Aumenta il grado di multiprogrammazione.
  Si carica solo ciò che serve di un programma. La
  memoria centrale può contenere molte più tracce.
Aumenta l'efficienza del caricamento.
  Si carica solo ciò che permette al programma di
  iniziare l'esecuzione.
Si possono effettuare allocazioni grandi.
  Il kernel assegna aree di indirizzi lineari. Solo in caso
  di effettivo utilizzo le pagine delle aree sono associate
  a frame liberi.
                                                         11
MEMORIA VIRTUALE

                   12
Memoria virtuale
           (Una estensione del concetto di paginazione)
Il meccanismo di memoria virtuale è una
estensione della tecnica di paginazione.
L'idea di base è quella di legare una pagina:
  ad un frame fisico (paginazione base).
  oppure ad un blocco di un file (novità).
  oppure ad un blocco del disco (novità).
In tal modo:
  alcune porzioni della memoria di un processo sono
  caricate in memoria, mentre altre no.
  alcune porzioni della memoria di un processo
  possono essere inserite in swap, mentre altre no. 13
Schema di memoria virtuale
              (Un diagramma vale più di 1000 parole)
pagina 0

pagina 1

pagina 2

   ...

pagina n

Memoria         Mappa di            Memoria               Unità di
virtuale        memoria              fisica            memorizzazione   14
                                                         secondaria
Spazio di indirizzamento lineare
                     (Di un processo)
Ad ogni processo è associato uno
spazio degli indirizzi (o spazio di Max         Stack
indirizzamento) lineare.
  Sequenza di indirizzi lineari a
  disposizione del processo.
  Organizzato per aree di memoria
  contigue (dette segmenti), con le             Heap
  porzioni del processo (codice, dati,
  stack).                                    Dati statici
  Gestito in maniera pigra (solo ciò     0
                                              Codice
  che serve effettivamente è caricato                       15
  in memoria).
Spazio di indirizzamento – x86                                       0xffffffff (4GB)
LASR: Linear Address                             Kernel
Space Randomization                                                                 0xc0000000 (3GB)
                                                                                     Random stack offset (LASR)
(per rendere i buffer
overflow più difficili)                           Stack
                                                                                     Random mmap offset (LASR)
                                  Segmento mappe di memoria                         mmap_base
Delle mappe di                Mappature su file: ad es. /lib/libc.so
memoria se ne                          Mappature anonime
parla più avanti                                                                    program break
in questa lezione                                 Heap                              brk
                                                                                    start_brk
                                                                                      Random brk offset (LASR)
I “segmenti” non sono                        Segmento BSS
quelli Intel! Nel gergo   Variabili statiche non inizializzate, riempite di zeri.
del kernel, il segmento             Esempio: static char *username;
è un'area di memoria                         Segmento dati                          end_data
lineare contigua.         Variabili statiche inizializzate dal programmatore.
                                  Esempio: static char *var = “value”;              start_data
                                        Segmento di testo (ELF)                     end_code
                           Immagine binaria del codice (ad es., /bin/ls)            0x08048000 (128MB) 16
                                                                                    0x00000000
Il descrittore di memoria in Linux
           (Rappresenta lo spazio di indirizzamento)

Il campo mm della task_struct di ciascun
processo utente contiene un puntatore al
descrittore di memoria che rappresenta lo
spazio di indirizzamento di un processo.
Esso è definito mediante la seguente struttura:
  struct mm_struct.
  File $LINUX/include/mm_types.h.
                                                       17
Alcuni campi importanti di mm_struct
        (Puntatori agli indirizzi lineari delle aree; si confronti slide 15)
start_stack: indirizzo iniziale dello stack.
mmap_base: indirizzo iniziale dell'area mmap.
start_brk, brk: inizio e fine dell'heap.
start_data, end_data: inizio e fine del segmento dati.
start_code, end_code: inizio e fine del segmento testo.
                                           start_stack                Stack
                                            mmap_base
   task_struct                                             Segmento mappe di memoria
                                                  brk
     (/bin/ls)             mm_struct                                  Heap
                     mm                     start_brk

    Descrittore di        Descrittore di     end_data             Segmento BSS
      processo              memoria
                                           start_data             Segmento dati
                                           end_code             Segmento di testo   18
                                      start_code
Rappresentazione aree di memoria
           (Ciascuna è descritta da una struttura dati)

I campi ora visti sono semplicemente indirizzi
lineari iniziali “notevoli”.
In Linux, ognuna delle aree viste (codice, dati,
stack, mappa) è rappresentata da una opportuna
struttura dati:
  struct vm_area_struct.
  File $LINUX/include/linux/mm_types.h.
Le aree di un processo in esecuzione sono visibili
con il comando pmap PID.
                                                          19
Indirizzi iniziali e finali dell'area
       (Memorizzati in due campi opportuni di vm_area_struct)

Gli indirizzi iniziali e finali dell'area di memoria
sono memorizzati in due campi della struttura
vm_area_struct.
  vm_start: indirizzo iniziale dell'area.
  vm_end: indirizzo successivo a quello finale dell'area.

                                                                20
Mappatura di memoria
          (Di file o di frame fisici; gestita in maniera pigra)
Le aree di memoria sono gestite in maniera pigra
tramite una mappatura di memoria (memory
map).
Le singole pagine dell'area puntano:
  ad un blocco di disco (4KB).
  ad un frame fisico (4KB).
  ad un blocco di una partizione di swap (4KB).
  a nulla (non sono state ancora mappate).
L'associazione avviene nel momento in cui la CPU
genera un indirizzo lineare nella pagina e vi
                                               21
accede.
Legame area memoria ↔ file su disco
      (La vm_area_struct ha un campo puntatore alla struct file)

Se l'area di memoria lineare è associata al
contenuto di un file su disco, l'area si dice
supportata da file (file-backed).
Il campo vm_file di vm_area_struct è un
puntatore alla struct file rappresentante il
file mappato.
                                                                   22
Trasporto dei blocchi in memoria
                 (Struct vm_operations_struct)
Le operazioni di mappatura del file variano da file
system a file system.
Si definisce una vm_operations_struct con
i puntatori alle funzioni di gestione:
  creazione mappa, distruzione mappa, fault, ...
Il campo vm_ops di vm_area_struct
contiene un puntatore alla struttura appropriata
per il file system ospitante il file da mappare.
  vm_area→vm_ops→fault() è invocata del page
  fault handler.                           23
Legame area memoria ↔ frame fisico
    (La vm_area_struct ha un campo puntatore alla struct anon_vma)

Se l'area di memoria lineare è associata a frame
fisici, l'area si dice anonima (anonymous).
Il campo anon_vma di vm_area_struct è un
puntatore           alla   struct      anon_vma
rappresentante il frame fisico mappato.

                                                                     24
I permessi di accesso
               (Lettura, scrittura, esecuzione)

Ciascuna area di memoria ha permessi di accesso
  VM_READ: in lettura.
  VM_WRITE: in scrittura.
  VM_EXEC: in esecuzione.
File $LINUX/include/linux/mm.h.
I permessi sono contenuti nel campo vm_flags
della vm_area_struct e sono usati dal kernel
per verificare la correttezza delle operazioni
richieste dagli utenti.                      25
Collegamento delle aree di memoria
         (Storicamente, tramite liste doppiamente collegate)

Storicamente, le vm_area_struct sono
sempre state collegate con una lista doppia.
  Campi vm_next, vm_prev.
  Problema: l'individuazione dell'area contenente
  l'indirizzo richiede una scansione lineare dell'intera
  lista → terribilmente inefficiente.
Oggi tali liste sono usate durante la fase di
costruzione dello spazio d indirizzamento del
processo (creazione, esecuzione).           26
Collegamento delle aree di memoria
 (Oggi, tramite alberi rosso-neri ordinati per indirizzo lineare iniziale dell'area)
Oggi si usano alberi rosso-neri ordinati per indirizzo
lineare iniziale dell'area di memoria.
   Lookup logaritmico nel numero di aree di memoria!
A ciascun nodo di un albero rosso-nero è associata una
struct rb_node che permette di risalire al nodo
padre ed ai nodi figli.
La vm_area_struct contiene un campo, vm_rb, di
tipo struct rb_node per l'inserimento nell'albero.
La radice dell'albero rosso-nero è contenuta nel nodo
mm_rb del descrittore di memoria del processo
(mm_struct).                                         27
Schema del collegamento
            (vm_area_struct collegata all'albero rosso-nero)

                                         struct
                                         rb_node
struct
 vm_area_struct {                  struct                      struct
                                  rb_node                      rb_node

struct rb_node
 vm_rb;
                                   struct        struct        struct
                                  rb_node       rb_node        rb_node
};

                                                                         28
vm_start

              Schema delle aree di memoria
                                  vm_area_struct
                                                                  vm_end
                                                                Stack
                        VM_READ | VM_WRITE | VM_GROWS_DOWN    (anonimo)
              vm_next
struct file                       vm_area_struct
              vm_file           VM_READ | VM_EXEC            Memory map
/lib/ld.so                                                    (supportato
              vm_next                                            da file)
 struct file vm_file              vm_area_struct
/lib/libc.so                    VM_READ | VM_EXEC
             vm_next
                                  vm_area_struct                Heap
                                VM_READ | VM_WRITE            (anonimo)
              vm_next
                                  vm_area_struct                 BSS
                                VM_READ | VM_WRITE            (anonimo)
              vm_next                                            Dati
                                  vm_area_struct
              vm_file           VM_READ | VM_WRITE           (supportato
struct file vm_next                                             da file)
  /bin/ls                         vm_area_struct                Testo
            vm_file             VM_READ | VM_EXEC            (supportato
                                                                da file)
         task_struct                      mmap
                                                                           29
           /bin/ls         mm       mm_struct
Individuazione dell'area di memoria
                (A partire da un indirizzo lineare)

È spesso necessario individuare l'area di memoria
che contiene (presumibilmente) un indirizzo
lineare.
  Esempio classico: controlli di accesso.
La funzione find_vma() scandisce l'albero
rosso-nero puntato da mm_rb e ritorna la
vm_area_struct più vicina o che contiene
l'indirizzo lineare.
  File $LINUX/mm/mmap.c.                              30
Individuazione di un'area libera
              (Per creare nuove aree di memoria)

Un     altro   compito      importante     consiste
nell'individuare un'area di memoria libera.
  Esempi classici: esecuzione immagine, creazione
  manuale di mappe anonime.
La funzione get_unmapped_area() scandisce
l'albero rosso-nero puntato da mm_rb e ritorna
un'area di memoria libera nell'area degli indirizzi
noti per il codice, i dati, le mappe o lo stack.
  File $LINUX/mm/mmap.c.                           31
Creazione di un'area di memoria
       (Dal kernel, per scopi interni o su comando del sistema)

La funzione insert_memory_region() crea
una nuova area di memoria e la inserisce sia nella
lista collegata, sia nell'albero rosso-nero delle
aree.
  File $LINUX/mm/mmap.c.
Solitamente è il kernel a creare aree di memoria.
Anche l'utente può crearne con la chiamata di
sistema mmap().
                                                                  32
Distruzione di un'area di memoria
       (Dal kernel, per scopi interni o su comando del sistema)

La funzione do_munmap() distrugge un'area di
memoria ed aggiorna la lista collegata e l'albero
rosso-nero delle aree.
  File $LINUX/mm/mmap.c.
Solitamente è il kernel a distruggere aree di
memoria. Anche l'utente può distruggere un'area
che ha creato esplicitamente con la chiamata di
sistema munmap().
                                                                  33
Spostamento di un'area di memoria
       (Se cresce troppo, può andare a sbattere contro un'altra)
Un problema importante da risolvere è la
sovrapposizione di due aree di memoria in
seguito alla crescita di una delle due.
Per evitarla, si può spostare un'area di memoria in
un altro intervallo di indirizzi lineari.
Tale funzionalità permette anche banalmente di
estendere un'area (si sposta un solo estremo).
La chiamata di sistema mremap() effettua lo
spostamento.
  File $LINUX/mm/mremap.c                                          34
Memory locking di un'area
             (L'area non viene più spostata su swap)
Si può decidere di non far mai inserire nell'area di
swap un'area di memoria.
→ Gli accessi avvengono sempre da memoria
centrale (veloci).
Attenzione: usare con cautela! Si rimuove
memoria centrale altrimenti disponibile.
La chiamata di sistema mlock() inchioda l'area
in memoria impostando il flag VM_LOCKED.
La chiamata di sistema munlock() toglie il lock.
  File $LINUX/mm/mlock.c                               35
PAGINAZIONE SU RICHIESTA

                           36
Definizione
                   (Demand paging)

Il meccanismo di paginazione su richiesta
(demand paging) fa uso della rappresentazione
delle aree di memoria per gestire in maniera pigra
lo spazio di indirizzamento di un processo.
Sforzo congiunto di:
  hardware (page fault, bit di accesso).
  kernel (gestione delle aree di memoria).
  librerie di sistema (caricamento del programma,
  creazione di aree di memoria).
                                                37
Uno schema con gli attori principali
                     (Chi collabora al demand paging?)
   Spazio di       Tabella                Spazio di         Unità di
indirizzamento   delle pagine          indirizzamento    memorizzazione
    lineare                                  fisico        secondaria
      A              4   v             0
 0
                         i             1
 1    B                                2
                     6   v             3
 2    C                  i             4                     A   B
                         i             5   C
 3    D
                                       6                     C   D
                     9   v
 4    E                                7
                         i             8                     E   F
 5    F                  i             9    F
                                      10
 6    G
                                                                          38
 7    H
Scenario d'uso
                      (Una demo vale più di 1000 parole)
    Spazio di          Spazio di          Spazio di           Unità di
 indirizzamento    indirizzamento      indirizzamento      memorizzazione
lineare processo    lineare kernel           fisico          secondaria
                     Codice

    load M

                     Tabella delle        Frame libero
                     pagine

                               i
                                                                            39
Scenario d'uso
                      (Una demo vale più di 1000 parole)
    Spazio di          Spazio di          Spazio di          Unità di
 indirizzamento    indirizzamento      indirizzamento
                                            Dall'indirizzomemorizzazione
                                                            M viene
lineare processo    lineare kernel           fisico         secondaria
                                          estratto il riferimento alla
                    Codice                tabella delle pagine.
    load M

                    Tabella delle        Frame libero
                    pagine

                              i
                                                                           40
Scenario d'uso
                      (Una demo vale più di 1000 parole)
    Spazio di          Spazio di          Spazio di           Unità di
 indirizzamento    indirizzamento      indirizzamento
                                            Il            memorizzazione
                                                riferimento èsecondaria
                                                               invalido.
lineare processo    lineare kernel           fisico
                                          Viene invocato il gestore
                    Codice                del page fault.
    load M

                    Tabella delle        Frame libero
                    pagine

                              i
                                                                           41
Scenario d'uso
                      (Una demo vale più di 1000 parole)
    Spazio di          Spazio di          Spazio di           Unità di
 indirizzamento    indirizzamento           Se l'indirizzomemorizzazione
                                       indirizzamento        è illegale
lineare processo    lineare kernel          per
                                             fisico il processo,  lo si
                                                             secondaria
                    Codice                termina con il segnale 11
                                          (segmentation fault).
      X
    load M

                    Tabella delle        Frame libero
                    pagine

                              i
                                                                           42
Scenario d'uso
                      (Una demo vale più di 1000 parole)
    Spazio di          Spazio di          Spazio    di
                                            Se l'indirizzo     Unità di
                                                             è mappato
 indirizzamento    indirizzamento      indirizzamento
                                            su   un   bloccomemorizzazione
                                                             del disco, si
lineare processo    lineare kernel           fisico           secondaria
                                           individuano la posizione
                    Codice                 del blocco ed un frame
                                           fisico libero in memoria.
    load M

                                                               A

                    Tabella delle        Frame libero
                    pagine

                              i
                                                                             43
Scenario d'uso
                      (Una demo vale più di 1000 parole)
    Spazio di          Spazio di          Spazio di            Unità di
 indirizzamento    indirizzamento      indirizzamento
                                            Il  blocco del memorizzazione
                                                            disco  viene
lineare processo    lineare kernel           fisico          secondaria
                                          trasferito     nel       frame
                    Codice                libero.
    load M

                                                               A

                    Tabella delle        Frame libero
                    pagine

                              i
                                                                            44
Scenario d'uso
                      (Una demo vale più di 1000 parole)
    Spazio di          Spazio di          Spazio di            Unità di
 indirizzamento    indirizzamento           Dopo il trasferimento
                                       indirizzamento                   si
                                                           memorizzazione
lineare processo    lineare kernel          aggiorna
                                             fisico    il bit secondaria
                                                              di validità
                    Codice                 nell'elemento         della
                                           tabella delle pagine.
    load M

                                                               A

                    Tabella delle        Blocco disco
                    pagine

                             v
                                                                             45
Scenario d'uso
                      (Una demo vale più di 1000 parole)
    Spazio di          Spazio di          Spazio di           Unità di
 indirizzamento    indirizzamento           Il processorememorizzazione
                                       indirizzamento       esegue di
lineare processo    lineare kernel          nuovo
                                             fisico       l'istruzione.
                                                            secondaria
                    Codice               Questa volta l'indirizzo
                                         contiene il dato richiesto.
    load M

                                                            A

                    Tabella delle       Blocco disco
                    pagine

                             v
                                                                          46
Tempo di accesso effettivo
            (Media ponderata di due componenti)

Il tempo di accesso effettivo alla pagina Teff è la
media ponderata dei tempi di due eventi
disgiunti.
  Tma: tempo di accesso in memoria senza page fault.
  Tge: tempo di accesso in memoria con page fault.
La media è ponderata sulla probabilità p ∈ [0, 1]
di avere un page fault. Si ha:
   Teff=(1-p)Tma+pTge=Tma+(Tge-Tma)p
                                                   47
Un esempio
          (Tanto per capire la pesantezza del page fault)

Siano dati i seguenti parametri:
  Tma=200ns, Tge=8ms, p=0.001.
Quanto vale Teff?
Teff= Tma+(Tge-Tma)p
      = 200ns+(8000000ns-200ns)*0.001
      = 200ns+7999800ns*0.001                               Peggiore di
      = 200ns+7999.800ns                                    Teff/Tma
      = 8.199800ns≃ 8.2μs                                   ≃8200ns/200ns
                                                            =41 volte! 48
Un altro esempio
       (Quanto deve valere p per peggiorare l'accesso del 10%?)

Siano dati i seguenti parametri:
   Tma=200ns, Tge=8ms.
Quanto deve valere al più p per avere Teff
degradato di al più il 10% rispetto a Tma? Errore relativo
[Teff(p)-Tma]/Tma≤ 0.1                    fra Teff e Tma
→ [200ns+7999800ns*p – 200ns]/200ns≤0.1
→ 200ns+7999800ns*p – 200ns≤20ns    Si deve verificare
→ 7999800ns*p ≤20ns                 al più un page fault
→ p≤20ns/7998000ns=0.0000025        ogni 1/0.0000025=
                                                       49
                                                     399990 accessi.
OTTIMIZZAZIONI

                 50
Problema: ripetizione di alcune aree
               (Tipicamente, il codice delle librerie)

Alcune aree di memoria sono presenti identiche
in ogni processo.
  Classico esempio: aree di testo delle librerie.
Ogni processo che parte dovrebbe, in linea di
principio, avere una copia di queste aree.
  → Enorme consumo di spazio.
Un esempio (esagerato).
  la macchina ha 200 processi attivi.
  ognuno vuole tutti i 1.7MB di testo della libreria del C.
→ Consumo complessivo: 200*1.7MB=340MB.                   51
Soluzione: condivisione delle pagine
(I processi hanno aree di memoria distinte che puntano agli stessi frame fisici)
Il kernel implementa un meccanismo di
condivisione delle pagine fra più processi.
Ad esempio, per tutti i processi dotati di un'area
per il testo della libreria del C:
   il kernel crea un'area di memoria.
   il kernel fa condividere gli stessi frame fisici caricati in
   memoria la prima volta.
Il risparmio di memoria è enorme.
   N utenti della libreria, una sola istanza in memoria.
La condivisione funziona in sola lettura.
                                                                               52
   Che succede se un processo modifica l'area?
Schema di condivisione
                     (Più processi usano la stessa memoria fisica)
Processo                               Memoria                                Processo
   P1          Stack                    fisica                   Stack           P2
                                     Frame testo
                                   /lib/libc.so
               Testo                 Frame testo                Testo
           /lib/libc.so            /lib/libc.so             /lib/libc.so
                                     Frame testo
                                   /lib/libc.so

               Heap                                              Heap

             Dati statici                                      Dati statici

               Codice                                            Codice           53
Problema: scrittura su aree condivise
        (Non si vuole propagare la modifica a tutti i processi!)

Cosa succede se, nello schema precedente, un
processo modifica il contenuto della memoria?
È di vitale importanza impedire che la modifica si
propaghi a tutti i processi!
Altrimenti, un processo potrebbe facilmente
distruggere lo spazio di indirizzamento di un
altro.
                                                                   54
Problema: esecuzione di un programma
           (Distrugge la mappatura creata da fork())

Cosa succede se, dopo una fork(), il processo
figlio esegue un programma diverso con la
chiamata di sistema execve()?
Le mappe di memoria create da fork() (codice,
dati, stack) sarebbero da rifare integralmente da
zero!
Si può migliorare questa inefficienza?
                                                       55
Soluzione: condivisione delle pagine
(I processi hanno aree di memoria distinte che puntano agli stessi frame fisici)

Il kernel implementa un meccanismo di
condivisione delle pagine fra più processi.
Ad esempio, per tutti i processi dotati di un'area
per il testo della libreria del C:
   alloca un nuovo frame fisico.
   copia nel nuovo frame fisico il contenuto del frame
   condiviso.
   associa la pagina al nuovo frame fisico.
Il COW risolve l'inefficienza fork()/exec()e
isola la memoria dei processi.             56
Schema di COW
           (Prima della modifica da parte di P1)
Processo                 Memoria                   Processo
   P1                     fisica                      P2

                            A

                            B

                            C

                                                              57
Schema di COW
           (Dopo la modifica da parte di P1)
Processo               Memoria                 Processo
   P1                   fisica                    P2

                          A

                          B

                          C

                        Copia C

                                                          58
ALLOCAZIONE DELLA MEMORIA

                            59
Allocazione dinamica della memoria
           (La vedremo meglio nell'esercitazione)

Gli strumenti di allocazione dinamica della
memoria in GNU/Linux sono i seguenti.
  Modifica dell'heap: brk().
  Creazione mappe di memoria: mmap(), munmap().
  Allocazione generale: malloc(), free().

                                                    60
Modifica dell'heap
     (Si alza e si abbassa l'asticella dell'heap, detta program break)

In Linux, due chiamate di sistema permettono di
modificare il valore del program break, ossia il
primo indirizzo lineare dopo l'heap.
  brk(): impostazione di un indirizzo lineare assoluto.
  sbrk(): incremento e decremento del program
  break.

                                                                         61
Creazione di mappe di memoria
             (Associate ad un file oppure anonime)
In Linux, due chiamate di sistema permettono di
creare e distruggere mappe di memoria.
  mmap(): creazione di una mappa.
  munmap(): distruzione della mappa.
Le mappe possono essere:
  associate a file o no.
  private ad un processo o condivise fra processi.
  su tutto un file o su una singola parte.
Attenzione: le mappe sono veramente condivise,
nel senso che le modifiche di un processo sono
                                             62
viste da un altro.
Allocazione dinamica della memoria
                      (By Doug Lea)
Un algoritmo di allocazione dinamica molto
popolare è dlmalloc.
  Creato nel 1987 da Doug Lea.
  Implementato (con alcune modifiche) nella GNU C
  Library.
L'algoritmo usa due meccanismi di allocazione
diversi a seconda della dimensione richiesta.
  Dimensione “piccola” (≤ 32 pagine): si espande l'heap.
  Dimensione “grande” (> 32 pagine): si crea una
  mappatura anonima.
→ Dettagli maggiori nell'esercitazione.               63
Motivazione
               (Uso dell'heap per allocazioni piccole)

Se l'allocazione è ragionevolmente piccola, basta
“alzare l'asticella” dell'heap.
   Lo spazio di indirizzamento logico cresce di poco (si
   richiedono pochi frame fisici).
Quando viene liberata la memoria, il SO non la
distrugge, bensì la mette a disposizione per
future allocazioni.
   Il SO non tocca i relativi elementi nella tabella delle
   pagine.
I frame fisici sono rilasciati “abbassando l'asticella”.64
Una conseguenza importante
                   (free() non fa nulla)

La free() non fa praticamente nulla.
→ Vantaggio prestazionale rispetto al caso più
generale di aggiornamento della tabella delle
pagine.
Perché non si usa sempre brk()?
  Non si può alzare l'asticella indefinitamente; si
  andrebbe a sbattere contro le mappe di memoria!
  I frame fisici non sono restituiti al SO; si perde
  memoria fisica.                                  65
Motivazione
             (Uso di mmap() per allocazioni grandi)
Se l'allocazione è grande, è mandatorio creare
una mappatura anonima con mmap().
→ Tale area di memoria può essere piazzata
ovunque nello spazio di indirizzamento, fra stack
e heap.
→ Non vi sono le sovrapposizioni viste in
precedenza con l'heap.
La memory_free() invoca la memory_unmap() per
distruggere la associazione indirizzi logici-frame
fisici.                                          66
Puoi anche leggere