Gestionarea memoriei

De la Wikipedia, enciclopedia liberă.
Salt la navigare Salt la căutare

Memoria principală a unui computer este o componentă fundamentală care susține conceptul de proces . Un proces, de fapt, care trebuie definit ca atare, adică un program în execuție , trebuie să aibă un spațiu de memorie disponibil în care să fie alocate datele și instrucțiunile programului în sine.

Ierarhiile memoriei

Cantitatea mare de date prezentă în mod normal într-un computer este stocată pe suporturi care pot avea caracteristici foarte diferite, în ceea ce privește timpul de acces, capacitatea și costul. Aceste suporturi sunt organizate ca o structură ierarhică în care la cel mai înalt nivel găsim dispozitivele de memorie mai lente, mai mari și mai puțin costisitoare; pe măsură ce coborâți în această ierarhie, mediile au capacitate din ce în ce mai mică, timp de acces din ce în ce mai mic și costuri mai mari. Obiectivul care trebuie atins este optimizarea raportului performanță / cost, obținându-se astfel performanțe comparabile cu cazul în care toate informațiile necesare sunt disponibile la nivelul cel mai scăzut al ierarhiei, cu un cost comparabil cu cazul în care sunt concentrate. la cel mai înalt nivel.

Într-un computer obișnuit , o ierarhie tipică a memoriei este cea în care hard disk-ul este situat la cel mai înalt nivel, unde informațiile sunt stocate permanent; imediat după este memoria principală (DRAM / SDRAM), cu capacitate mare în ordinea GB, cost redus și timp de acces redus. Aici sunt stocate informațiile despre procesele care rulează: când se încarcă un proces nou, cel puțin informațiile de bază care vor permite să fie pornite vor fi transferate către acesta. În cazul în care acest nivel al ierarhiei este saturat, vor fi adoptate politici de optimizare care ar putea consta în compactarea memoriei în swap-out [1] a paginilor, care constă în transferul de informații la nivelul superior, adică pe hard disk .

La nivelurile inferioare avem memoria cache ; pot exista mai multe niveluri ale acestui tip de memorie și sunt indicate în mod normal cu o serie descrescătoare de numere pe măsură ce coborâți în ierarhie. În mod normal, nivelul cache L1 este „on-chip”, adică este direct prezent în CPU în așa fel încât să reducă fizic latența conexiunilor. Cel mai mic nivel al ierarhiei este cu siguranță reprezentat de registrele procesorului [2] al căror timp de acces poate fi evaluat într-un ciclu de ceas [3] .

Tehnici de gestionare a memoriei

Un mecanism de gestionare a memoriei poate fi identificat prin patru parametri fundamentali, cum ar fi:

  • relocare: statică sau dinamică
  • spațiu virtual: unic sau segmentat
  • alocarea fizică a memoriei: contiguă sau necontinuă
  • încărcare spațiu virtual: toate dintr-o dată sau la cerere.

Cu excepția câtorva, fiecare combinație a acestor patru factori are o tehnică de gestionare a memoriei corespunzătoare.

Relocare

Adresele generate de procesorul pe care rulează un proces se numesc adrese „logice” sau „virtuale” și se referă la memoria virtuală a procesului în sine. Aceste adrese, însă, nu corespund neapărat adreselor în care informațiile căutate sunt de fapt puse la dispoziție, adică „adresele fizice”, din acest motiv este necesar să fie pus în aplicare un mecanism care să permită potrivirea adreselor logice cu adresele fizice: relocarea statică asigură, de fapt, că la încărcarea procesului, „încărcătorul”, care în acest moment cunoaște zona de memorie fizică unde va fi încărcată memoria virtuală a acestuia, înlocuiește toate adresele logice care pot fi generat, în adresele fizice corespunzătoare.

Dacă, pe de o parte, această politică vă permite să salvați orice cheltuieli generale datorită traducerii adreselor logice în timpul rulării, timpul care va fi petrecut în momentul încărcării, pe de altă parte, nu este potrivit în cazul în care sunt adoptate politici de schimb, deoarece, de fiecare dată când o zonă de memorie descărcată anterior este schimbată în [4] , poate fi necesară mutarea din nou a tuturor adreselor.

Spațiu virtual

Memoria virtuală a unui proces în care există toate informațiile necesare pentru executarea acestuia, cum ar fi codul, zona rezervată stivei și datele , poate fi structurată ca un spațiu de adrese contigu, adică cu adrese de la 0 la N, unde N reprezintă dimensiunea memoriei virtuale sau poate fi împărțită în segmente independente, cum ar fi un segment pentru cod, un segment pentru stivă și în cele din urmă unul pentru date . În al doilea caz, conceptul de a putea aplica diferite permisiuni de citire / scriere pentru fiecare segment este mai natural.

Alocarea fizică a memoriei

Definește modul în care ar trebui ales spațiul de memorie fizică care urmează să fie alocat procesului. Presupunând că suntem în cazul unui singur spațiu virtual , atunci când acesta trebuie încărcat în memorie, este necesar să se identifice o zonă liberă de dimensiuni mai mare sau egală cu N, unde N reprezintă dimensiunea spațiului de adresă; dacă, prin ipoteză, ar fi disponibile mai multe zone cu dimensiuni mai mici decât N, acestea nu ar putea fi selectate chiar dacă suma dimensiunilor lor ar fi mai mare sau egală cu N.

În cazul spațiului virtual segmentat , problema poate fi urmărită înapoi la cea descrisă mai sus, deoarece fenomenul nu s-ar produce acum la nivelul întregului spațiu de adrese, ci al segmentului unic, chiar dacă în acest mod probabilitatea găsirea unei partiții de dimensiuni suficiente, deoarece dimensiunea segmentului unic este mai mică decât cea a întregii memorii virtuale .

Fenomenul tocmai descris se numește „fragmentare” și reprezintă o problemă de optimizare a gestionării memoriei, deoarece tinde să-și reducă utilizarea. În sistemele cu relocare dinamică, problema fragmentării poate fi rezolvată prin compactarea memoriei. În aceste sisteme, de fapt, se adoptă o funcție, numită funcția de relocare, care permite ca fiecare adresă virtuală să fie potrivită cu adresa fizică corespunzătoare; prin exploatarea acestei caracteristici, dacă se solicită o zonă de memorie contiguă de dimensiunea N, dar memoria este fragmentată, zonele libere ar putea fi compactate într-o singură zonă de dimensiune egală cu suma celor precedente. Această modificare nu va afecta executarea altor procese atunci când funcția de relocare este actualizată la noua stare de memorie. În cazul relocării statice, alocarea memoriei fizice trebuie să fie neapărat contiguă; de fapt, în acest caz adresele sunt traduse la momentul încărcării și rezultă că adresele fizice contigue trebuie să corespundă adreselor virtuale contigue.

Un exemplu clar despre cum nu poate fi altfel poate fi obținut gândindu-ne la bucla de preluare-executare [5] a procesorului , care va căuta următoarea instrucțiune de executat la următoarea adresă virtuală comparativ cu cea a instrucțiunii a cărei execuție tocmai a încheiat ; dacă memoria virtuală nu ar fi alocată contiguu, este evident că acest model ar eșua.

Încărcare spațiu virtual

Indică dacă spațiul virtual trebuie încărcat în memorie în întregime, copiindu-l de pe disc în memoria principală sau dacă trebuie încărcată doar o parte, posibil chiar minimă, cum ar fi doar descriptorul procesului. În acest din urmă caz, atunci când este generată o adresă logică care se referă la o zonă de memorie virtuală care nu este încă prezentă în memoria principală , se ridică o excepție numită eroare de pagină , a cărei gestionare va duce la o copie a acesteia din urmă în memoria principală .

Partiții

Partiții fixe sau variabile

Această tehnică nu utilizează mecanisme hardware pentru a sprijini gestionarea memoriei ( MMU ), efectuând relocarea statică a adreselor virtuale prin intermediul încărcătorului de relocare. Alocarea memoriei fizice se face contiguu, spațiul virtual este unic și totul este încărcat împreună. Memoria este împărțită în N partiții fixe, adică cu o anumită adresă de pornire și dimensiune, dintre care una este rezervată sistemului de operare, în timp ce celelalte sunt disponibile pentru a găzdui spațiul virtual al proceselor.

Când se începe un proces, dacă există partiții libere, partiția de dimensiune minimă va fi aleasă dintre cele a căror dimensiune este mai mare sau egală cu dimensiunea spațiului virtual al procesului în sine; dacă o partiție cu aceste caracteristici nu există sau toate partițiile sunt ocupate, spațiul virtual al unui proces este schimbat, cu constrângerea că atunci când trebuie să înceapă să ruleze din nou, swap-in-ul trebuie să se facă în aceeași partiție unde locuia anterior. Această constrângere se datorează adoptării relocării statice. Este evident că probabilitatea de a găsi partiții cu aceeași dimensiune a spațiului virtual al procesului care este încărcat din când în când este destul de scăzută, rezultă că diferența dintre dimensiunea partiției selectate și dimensiunea memoriei virtuale constituie o zonă de memorie neutilizată.

Având în vedere aceste zone în mod individual, acestea pot avea o dimensiune neglijabilă, în timp ce suma dimensiunilor lor poate constitui o parte considerabilă din memoria neutilizată. Acest dezavantaj se numește „fragmentare internă”. Acest model de gestionare a memoriei se pretează bine la alocarea dinamică a memoriei proceselor, adică implementarea politicilor de schimb. În acest sens, o listă de descriptori de proces este păstrată pentru fiecare partiție, adică toate acele procese cărora le-a fost atribuită acea partiție particulară. Primul descriptor din listă aparține procesului alocat în prezent în acea partiție în timp ce ceilalți sunt rezidenți în zona de swap. Periodic, în urma unei politici round-robin , memoria este revocată la primul proces al fiecărei partiții, descriptorul său este plasat în partea de jos a listei, iar partiția este alocată procesului următor în aceeași. În concluzie, schema de partiții fixe, datorită simplității sale, necesită o cheltuieli generale reduse pentru gestionarea partițiilor, totuși merită remarcat lipsa totală de flexibilitate datorită dimensiunii fixe a partițiilor care nu pot fi adaptate la dimensiunea spațiul virtual al proceselor care sunt încărcate din când în când.

Schema de gestionare a memoriei cu partiții variabile, pe de altă parte, vă permite să definiți dinamic caracteristicile partițiilor individuale în așa fel încât să corespundă nevoilor proceselor care sunt alocate din când în când. Inițial, toată memoria constă dintr-o singură partiție liberă de mărimea K; când se încarcă un nou proces cu memorie virtuală de dimensiunea N, se creează o partiție de dimensiunea exact N. În acest moment memoria este împărțită în două partiții: una în care este alocat procesul menționat anterior și de dimensiunea N, cealaltă disponibilă pentru găzduiește noi procese de dimensiuni KN.

Când un proces se încheie prin eliberarea partiției ocupate, nu creează neapărat o nouă partiție gratuită. Dacă zona de memorie care este eliberată este adiacentă altor partiții libere, toate sunt compactate într-o singură partiție a cărei dimensiune este egală cu suma lor. Schema de alocare cu partiții variabile este mai flexibilă decât cea cu partiții fixe; de fapt, nevoia de a defini partițiile în timpul fazei de instalare a sistemului se pierde, deoarece fiecărui proces i se alocă o zonă de memorie exact cu aceeași dimensiune ca și memoria virtuală a procesului, eliminând astfel problema fragmentării interne. Cu toate acestea, această schemă suferă și de un tip de fragmentare, și anume „fragmentare externă”, care apare atunci când partițiile libere individuale sunt mai mici decât cantitatea de memorie necesară, chiar dacă suma lor este mai mare decât cea din urmă. Adoptarea acestei scheme de alocare implică necesitatea de a urmări partițiile gratuite; acest lucru se face prin organizarea partițiilor ca noduri într-o listă.

Fiecare partiție din primele două locații de stocare indică dimensiunea și adresa următoarei partiții gratuite. Această listă poate fi organizată în conformitate cu două politici: prima, „cea mai potrivită”, necesită ca lista să păstreze partițiile libere în mod ordonat prin mărirea dimensiunii. În acest fel, la solicitarea unei partiții, lista este derulată până când se găsește o partiție cu o dimensiune mai mare sau egală cu zona de memorie solicitată. Odată ce partiția potrivită a fost găsită, aceasta „taie” ad-hoc pentru procesul încărcat, creând o nouă partiție gratuită care va contribui la fenomenul fragmentării memoriei sau va fi compactată la orice partiții libere adiacente. În faza de lansare, lista trebuie scanată în întregime pentru a verifica prezența partițiilor libere adiacente pentru a efectua compactarea. O a doua politică de gestionare a listei de partiții gratuite se numește „first-fit” și constă în păstrarea listei organizate prin păstrarea partițiilor ordonate la adresele lor; este evident că această schemă este deosebit de eficientă în faza de lansare, deoarece în căutarea partițiilor libere adiacente sunt luate în considerare elementul anterior și următorul din listă.

Partiții multiple

Această schemă, care poate fi adoptată în cazul spațiului virtual segmentat, prevede că unui singur proces nu i se alocă o singură partiție egală cu spațiul virtual al procesului, ci un număr egal cu numărul segmentelor sale. Prin segmentarea spațiului virtual , de exemplu în segmentele „ cod ”, „ stivă ” și „ date ”, este posibil să se permită partajarea segmentelor între procese. Gândindu-ne, de exemplu, la segmentul „cod”, pot fi executate mai multe procese care execută același program, dar pe date diferite; această schemă vă permite să partajați segmentul „cod” în așa fel încât să optimizați gestionarea memoriei. După ce am rupt memoria virtuală a procesului în segmente mai mici, am reduce, fără a-l elimina, fenomenul de fragmentare.

Segmentare

Pentru a elimina fenomenul fragmentării memoriei ar fi necesar să se prevadă compactarea acestuia, dar acest lucru nu este posibil sau mai degrabă nu este luat în considerare din punct de vedere al eficienței dacă se adoptă relocarea statică a adresei. Prin adoptarea, în schimb, a relocării dinamice sau prin traducerea adreselor logice în adrese fizice printr-o funcție adecvată de relocare posibil implementată în hardware ( MMU ), putem compacta memoria având singura consecință de a trebui să actualizăm această funcție de relocare.

În cazul memoriei virtuale segmentate, MMU trebuie să conțină mai multe perechi de registre de bază / limită, câte unul pentru fiecare segment în care este împărțită memoria. Registrele de bază / limită ale unui segment conțin adresa fizică de bază unde a fost alocat segmentul și dimensiunea acestuia. Când procesorul generează o adresă virtuală, se ia în considerare perechea de bază / registre limită a segmentului căruia îi aparține adresa generată. De exemplu, dacă adresa este generată la preluarea unei instrucțiuni, aceasta se va referi cu siguranță la segmentul „cod”. În acest moment, adresa virtuală este comparată cu valoarea conținută în registrul limită: dacă prima este mai mare, va fi generată o excepție, deoarece adresa solicitată nu aparține segmentului, altfel valoarea prezentă în registrul de bază va fi să fie adăugate, obținându-se adresa fizică la care informațiile solicitate sunt de fapt puse la dispoziție. Aceasta este o posibilă implementare a funcției de relocare.

Dacă memoria virtuală este împărțită numai în segmente „cod”, „stivă” și „date”, este ușor de identificat, pentru fiecare adresă generată de procesor , cărui segment îi aparține: dacă este generată atunci când o instrucțiune sau în timpul executarea instrucțiunilor de săritură și / sau săritură către un subrutină, aceasta va aparține segmentului „cod”; toate adresele generate în timpul executării instrucțiunilor push / pop aparțin segmentului „stivă” și, în cele din urmă, adresele generate în timpul executării celorlalte instrucțiuni aparțin segmentului „date”. Această schemă de alocare permite, de asemenea, o implementare mai ușoară a mecanismului de swap, de fapt, swap-in-ul unui segment nu mai există constrângerea de a trebui să îl alocați în aceeași partiție ocupată înainte de revocare, deoarece alegerea unei partiții diferite pur și simplu implică actualizarea registrelor de bază / limită corespunzătoare.

Cazul descris tocmai se limitează la luarea în considerare a faptului că memoria virtuală este împărțită în doar trei segmente, totuși nu există niciun motiv logic pentru a constrânge linkerul să facă această alegere. Memoria virtuală a unui proces poate fi împărțită într-un număr nedeterminat de segmente semnificative semantic, posibil limitat de arhitectură. Acest pas implică două probleme: prima este de natură logică și constă în imposibilitatea supremă de a determina „automat” segmentul căruia îi aparține o adresă virtuală generată. De fapt, dacă putem determina că o adresă generată în timpul fazei de preluare aparține segmentului „cod”, dacă există mai multe segmente „cod” nu putem determina care dintre acestea aparține exact. A doua problemă este de natură structurală și derivă din faptul că numărul de perechi de registre bază / limită conținute în MMU nu poate fi excesiv de mare. Prima problemă este rezolvată prin faptul că procesorul nu mai generează o singură adresă logică, ci o pereche <sg, off>, unde sg reprezintă indicele segmentului și off este offset-ul din segment.

În ceea ce privește a doua problemă, este introdusă o structură de date tabulare, păstrată în zona de memorie rezervată sistemului de operare, numită tabel de segmente, ale cărei înregistrări constau din adresa de bază / perechea limită a fiecărui segment, denumită adesea descriptori de segmente. MMU menține doar o pereche de registre numite respectiv STLR (Segment Table Limit Register), care conține dimensiunea tabelei de segmente și STBR (Segment Table Base Register), care conține adresa de bază a tabelului de segmente. Când se generează o adresă virtuală în format <sg, off>, MMU compară sg cu STLR: dacă prima este mai mare sau egală cu a doua, se aruncă o excepție, deoarece se face referire la un segment inexistent, în caz contrar, este accesat la adresa de bază / perechea limită prin adăugarea valorii sg la STBR. Odată obținută această pereche, aceasta este comparată cu valoarea care indică dimensiunea segmentului; din nou, dacă prima este mai mare sau egală, se aruncă o excepție, altfel se adaugă valoarea care indică adresa de bază a segmentului, obținându-se astfel adresa fizică.

Utilizarea tabelului de segmente implică o pierdere considerabilă de eficiență de către CPU, de fapt, pentru fiecare adresă virtuală generată este necesar să se facă două accesări în memorie: unul pentru a obține perechea adresă de bază / limită a segmentului la care se adresează această adresă se referă și unul pentru a accesa efectiv informațiile solicitate. Pentru a depăși această problemă, un număr variabil (de la 4 la 8) de registre asociative sunt păstrate în MMU; ori de câte ori este generată o adresă virtuală, se verifică mai întâi dacă descriptorul de segment căruia îi aparține adresa este conținut în această memorie de registru, numită și TLB (Translation Lookaside Buffer): dacă este conținută, traducerea se efectuează fără acces suplimentar în memorie, în caz contrar accesul se face prin stocarea descriptorului de segment tocmai recuperat în TBL, eventual aruncându-l pe cel menționat mai puțin recent. Luând în considerare principiul localității adreselor, cu puținele registre asociative prezente în MMU, este posibil să se traducă 80% din adrese fără a accesa tabelul de segmente. Această schemă permite definirea unor politici mai precise în ceea ce privește partajarea și protecția, oferind posibilitatea de a asocia permisiunile de citire / scriere și partajare pentru fiecare segment, adăugând câmpuri adecvate descriptorului segmentului.

Segmentarea cererii

Memoria segmentată se referă la o schemă care necesită încărcarea completă a memoriei virtuale a procesului în memoria fizică. Există, prin urmare, două condiții posibile: una este ca procesul, deci toate segmentele care alcătuiesc memoria sa virtuală , să fie alocate în memorie, cealaltă este că, în schimb, procesul a fost mutat în zona de swap. În acest moment este necesar să adăugați două stări noi la cele în care poate fi găsit un proces (gata, blocat, rulat), adică cele care corespund „gata” și „blocat”, dar cu spațiu virtual nealocat în memorie .

La apelarea swap-out-ului primitiv într-un proces aflat în starea „gata” sau „blocat”, starea acestuia se schimbă fie în „gata-swap”, fie „blocat-swap”. Reversul este adevărat dacă swap-in-ul primitiv este invocat pe un proces care a fost schimbat. Încărcarea memoriei virtuale a unui întreg proces în memoria fizică creează o constrângere asupra dimensiunii primului; de fapt, suma dimensiunilor tuturor segmentelor care alcătuiesc memoria virtuală a unui proces trebuie să fie mai mică decât dimensiunea totală a memoriei fizice. Pentru a elimina această constrângere putem adopta o politică la cerere privind gestionarea segmentelor. Un segment este încărcat în memorie numai atunci când este generată o adresă virtuală care îi aparține; în acel moment este generată o excepție de către MMU care comunică evenimentul (segment-defect) procesorului , care va executa un handler adecvat care, comunicând cu managerul de memorie, va permite ca segmentul solicitat să fie încărcat în memorie, permițând finalizați recuperarea informațiilor solicitate.

Când se face o cerere pentru un segment care nu este prezent în memorie, dacă acesta din urmă este găsit plin, unul sau mai multe segmente ale aceluiași proces sau ale altor procese sunt mutate în zona de swap. Cu această tehnică, faza de încărcare a unui proces devine mai eficientă, de fapt nu mai este necesar să copiați părți ale memoriei virtuale în memoria fizică, deoarece acest lucru se va face numai atunci când este necesar.

Implementarea segmentării cererii necesită adăugarea unui câmp de un bit la descriptorul segmentului, indicând prezența sau absența segmentului în memorie. Pentru a facilita implementarea oricăror algoritmi de înlocuire a segmentelor, pot fi adăugate alte câmpuri la descriptorul segmentului, cum ar fi bitul U, care este setat periodic la 0, prin software și setat la 1, prin hardware, de fiecare dată când se face. la segment sau la bitul M, care indică dacă segmentul a fost modificat sau nu; dacă M este setat la 0, adică segmentul nu a fost modificat, nu este necesar să îl rescrieți în zona swap când și dacă acesta va fi ales ca segment de înlocuit.

Memorie paginată

Problema fragmentării poate fi rezolvată parțial prin adoptarea schemei de memorie segmentată și aplicarea tehnicii de compactare care, totuși, necesită o cheltuială generală deloc neglijabilă. Această problemă ar putea fi rezolvată dacă am putea aloca adrese virtuale adiacente în memoria fizică adreselor non-adiacente. Pentru a face acest lucru, ar fi suficient să implementați funcția de relocare în așa fel încât fiecare adresă virtuală să corespundă cu adresa fizică atribuită. Se înțelege imediat că această implementare ar consta dintr-un tabel de corespondență de exact aceeași dimensiune ca memoria virtuală , penalizând performanța. Prin urmare, trebuie să se ajungă la un compromis prin împărțirea spațiului virtual în seturi de adrese virtuale adiacente, numite pagini: o pagină trebuie alocată într-o zonă de memorie adiacentă, două pagini nu trebuie neapărat să fie alocate în porțiuni adiacente de memorie. Funcția de relocare este acum realizabilă utilizând un tabel de corespondență între paginile virtuale și paginile fizice.

Fiecare adresă virtuală generată este împărțită în două părți: prima indică indexul paginii virtuale, a doua este offset-ul în cadrul paginii. Traducerea adresei virtuale într-o adresă fizică are loc acum prin accesarea tabelului de pagini cu indexul paginii virtuale, pentru a obține adresa de bază a paginii fizice corespunzătoare; adresa fizică se obține prin adăugarea la aceasta din urmă a decalajului indicat în adresa virtuală generată (paginile virtuale sunt alocate în poziții contigue ale memoriei fizice). Mărimea tabelului de corespondență depinde de numărul de pagini care alcătuiesc memoria virtuală a procesului , care, la rândul său, depinde de dimensiunea unei singure pagini. Presupunând o mașină cu adrese de 32 de biți și o dimensiune a paginii de 1024 de adrese, adresabilă, prin urmare, cu 10 biți, compensarea paginii va fi indicată în cei 10 biți cei mai puțin semnificativi ai adresei virtuale; Rămân 22 de biți (cei mai semnificativi) care sunt disponibili pentru indexul paginii virtuale, cu un total de 2 ^ 22 de pagini virtuale posibile. Este evident că tabelul de pagini nu poate fi alocat în MMU și, prin urmare, trebuie alocat în memoria fizică, urmărind, într-un registru adecvat, adresa de bază a tabelului; acest registru este denumit în mod obișnuit cu acronimul RPTP (Page Table Pointer Register).

Pentru a reduce numărul de accesări la tabelul de pagini, în MMU există un număr variabil de registre asociative (de la 4 la 8) în care sunt menținute corespondențele dintre paginile virtuale și paginile fizice la care au fost referite cel mai recent. Memoria de registru nou definită se mai numește TLB (Translation Lookaside Buffer). Atunci când este generată o adresă virtuală, se verifică dacă corespondența dintre indexul de pagină virtuală indicat în adresa generată și indexul de pagină fizic corespunzător este prezentă în TLB; dacă această verificare are succes, traducerea adresei se face fără acces suplimentar la memorie, în caz contrar se accesează tabelul de pagini, se efectuează traducerea și abia atunci se recuperează informațiile dorite. Înregistrarea tabelului de pagini, recuperată odată cu accesul la memorie realizat, este stocată în TLB, eventual aruncând-o pe cea la care s-a făcut referire mai puțin recent. Managerul de memorie fizică, la rândul său, menține actualizată lista paginilor fizice disponibile, în propriul tabel, unde pentru fiecare element este raportat dacă pagina este ocupată sau nu și, dacă este, indexul procesului la care a fost atribuit. Quando un processo deve essere caricato, viene richiesto al gestore della memoria il numero di pagine necessarie a contenerlo; se non sono disponibili un numero sufficiente di pagine fisiche, si provvederà a deallocare pagine virtuali dello stesso processo o di altri processi, provocandone lo swap-out. Un aspetto importante è la dimensione delle pagine.

Al diminuire di questa, aumenta la dimensione delle tabella delle pagine; al limite sarà uguale al numero di posizioni della memoria virtuale , rendendo la non contiguità delle posizioni completa. Al crescere della dimensione delle pagine assistiamo nuovamente ad una forma di frammentazione interna che si verificherà sulla pagina fisica che contiene l'ultima pagina virtuale del processo, a meno che la dimensione della memoria virtuale non sia un multiplo di quella delle pagine. Il fenomeno della frammentazione in caso di dimensione della pagine elevata, può verificarsi anche in altri casi: si pensi ad un insieme di dati che un processo vuole condividere, poiché i diritti di accesso e condivisione sono riportati sul descrittore di pagina virtuale e quindi si riferiscono alla singola pagina, tali dati saranno disposti in una pagina a sé stante, sul cui descrittore sarà impostato il flag di condivisione; nuovamente, se la dimensione di tale insieme non sarà un multiplo della dimensione della pagina, si verifica il fenomeno della frammentazione. Per ovviare a questi problemi, occorre individuare un compromesso sulla dimensione delle pagine, i cui valori tipici oscillano tra i 512 byte ei 4 KB. Un ulteriore aspetto riguardante la condivisione consiste nel tener presente che quando due processi condividono strutture dati, all'interno di queste possono essere presenti riferimenti (puntatori) al altre posizioni di memoria; questo dà luogo ad un problema definito come problema dei riferimenti indiretti in strutture dati condivise e può essere risolto in quattro modi:

  • Riferimenti logici distinti: nelle strutture condivise non sono presenti gli indirizzi virtuali ma degli identificatori unici. Ogni processo possiede nel suo spazio degli indirizzi una tabella che mette in corrispondenza tali identificatori con gli indirizzi logici del suo spazio di indirizzamento.
  • Riferimenti logici coincidenti: pone vincoli alla progettazione del compilatore, in particolare per quanto riguarda la compilazione separata. Gli indirizzi logici a cui si fa riferimento nella struttura dati condivisa devono essere coincidenti nei processi che effettuano la condivisione.
  • Riferimenti fisici: adottabile solo se l'architettura sottostante permette una distinzione tra indirizzi fisici e indirizzi logici. Nelle strutture dati condivise sono presenti direttamente gli indirizzi fisici e non quelli logici.
  • Adozione delle capability: nelle strutture dati condivise non sono presenti degli indirizzi logici ma un'indicazione al processo che ne fa uso su come tradurre l'indirizzo logico assegnato in indirizzo fisico, ovvero l'entrata della tabella di rilocazione del processo che ha iniziato la condivisione.

Paginazione a domanda

Con la tecnica della paginazione si ha il vincolo di dover caricare lo spazio virtuale di un processo per intero perché questo sia eseguibile, tuttavia l'adozione di una politica di caricamento di uno spazio virtuale a domanda porta ad una maggiore flessibilità nella gestione della memoria, permettendo di non tenere in memoria parti dello spazio virtuale che magari non verranno neanche mai usate. Tale politica può essere implementata aggiungendo al descrittore di pagina il bit di presenza e altri, per facilitare l'implementazione di algoritmi di rimpiazzamento. Quando viene generato un indirizzo virtuale, la MMU verifica, accedendo alla tabella di rilocazione , se il bit di presenza è settato a uno: la pagina è presente in memoria e l'indirizzo fisico si ottiene sommando all'indice di pagina fisica ricavato, l'offset indicato nell'indirizzo generato. Se il bit di presenza viene trovato a zero, la MMU genera un'eccezione (fault di pagina) che verrà gestita da un opportuno handler che provvederà al caricamento in memoria della pagina virtuale richiesta. Nel caso tutte le pagine fisiche siano occupate si provvederà al rimpiazzamento di una pagina dello stesso processo o di un processo diverso. Lo swap-out delle pagine deve tener conto di un importante aspetto: un processo può essere stato posto in stato di bloccato in quanto sta attendendo il completamento di un trasferimento I/O da un dispositivo alla memoria principale e magari ad un buffer allocato in una pagina fisica X. Tale trasferimento avviene attraverso il canale DMA, il bus I/O infatti non può essere usato da un processo in stato “bloccato” in quanto questo si interfaccia direttamente con la CPU . Se la pagina X viene scelta come pagina da rimpiazzare, copiando il suo contenuto nella swap-area, e associandovi un'altra pagina virtuale, dello stesso o di un diverso processo, il trasferimento I/O andrebbe a creare una situazione inconsistente in quanto la copia sarebbe fatta in posizioni diverse da quelle di destinazione. Per ovviare a tale problema è presente nei descrittori di pagina fisica un ulteriore bit, detto bit di lock, che se posto a 1 indica all'algoritimo di rimpiazzamento delle pagine che quella pagina non può essere scelta.

Memoria segmentata e paginata

Le tecniche della segmentazione e della paginazione possono sembrare molto simili tra loro ma in realtà sono profondamente diverse. Mentre la prima si propone di suddividere la memoria virtuale in moduli semanticamente significativi ed indipendenti tra di loro, quindi non più concependola come una piatta sequenza di bytes, la seconda, invece, si propone di suddividere la memoria virtuale in insiemi di posizioni, le pagine, senza interessarsi della semantica e in modo da permettere l'allocazione della memoria fisica in maniera non contigua, eliminando così il fenomeno della frammentazione. È possibile definire una tecnica che prevede sia la strutturazione della memoria virtuale in segmenti, sia la suddivisione di ogni segmento in un insieme di pagine. Utilizzando tale tecnica, gli indirizzi virtuali vanno visti come coppie <sg, sc> dove sg rappresenta l'indice del segmento e sc lo scostamento all'interno del segmento. All'atto della traduzione viene recuperato il descrittore di segmento individuato da sg che contiene due campi: base e limite. Il campo base non indica più l'indirizzo base della partizione in cui è stato allocato il segmento desiderato, ma l'indirizzo della tabella delle pagine relativa a quel segmento. Ogni segmento ha una propria tabella delle pagine. Il valore sc viene, a sua volta, suddiviso in due campi: i bit meno significativi costituiscono l'offset all'interno della pagina, mentre quelli più significativi indicano l'indice di pagina virtuale mediante il quale è possibile recuperare il descrittore di pagina virtuale. A questo punto, se si adotta una politica di paging on demand, viene fatto il controllo sul bit di presenza ed eventualmente generato un fault di pagina, altrimenti, sommando all'indirizzo base della pagina fisica, letto dal descrittore appena recuperato, l'offset presente nei bit meno significativi di sc si ottiene l'indirizzo fisico.

Note

  1. ^ Azione 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.
  2. ^ Costituiscono 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.
  3. ^ Interavallo 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.
  4. ^ Azione 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.
  5. ^ Il 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.

Bibliografia

  • Andrew S.Tanenbaum. Modern Operating Systems . ISBN 0-13-813459-6 . Pearson Education, Upper Saddle River, NJ 07458, 2009
  • Paolo Ancilotti, Maurelio Boari, Anna Ciampolini, Giuseppe Lipari. Sistemi operativi . ISBN 88-386-6069-7 . McGraw-Hill, 2004
  • Marco Vanneschi. Architettura degli elaboratori SEU, Pisa, 2008

Altri progetti

Controllo di autorità LCCN ( EN ) sh90003066 · GND ( DE ) 4182146-4
Informatica Portale Informatica : accedi alle voci di Wikipedia che trattano di informatica