La gestió de memòria a Linux

La gestió de memòria és una part clau en l’eficiència d’un sistema operatiu, i en aquest post descobrirem com funciona a Linux.

En sistemes sense memòria virtual, on tenim un únic espai d’adreces compartit entre memòria i perifèrics, es presenten certs problemes:

  • Memòria no protegida

  • Els processos poden “aixafar-se” entre si

  • L’espai d’usuari pot interactuar amb memòria del kernel

A més, gestionar diferents processos és complex, ja que s’han de mantenir separats però cadascú ha de tenir les seves zones de memòria ben definides.

Aquí és on entra en joc la memòria virtual.

És una solució al problema de l’espai de memòria únic: un sistema que utilitza mapatge d’adreces:

  • Mapeja adreces virtuals a adreces de RAM física

  • Mapeja adreces virtuals a dispositius de hardware

Gràcies a la memòria virtual, cada procés té un espai d’adreces separat de la resta. Això ens ofereix molts avantatges com:

  • Tenir mapatges diferents per cada procés

    • Els processos són invisibles entre si

    • La memòria del kernel també és invisible per als processos en espai d’usuari

  • La memòria es pot moure

  • La memòria pot canviar a disc (swap)

  • La mateixa àrea de memòria pot estar mapejada a diferents processos alhora (memòria compartida)

  • Les regions de memòria poden tenir permisos d’accés

Llavors tenim 2 espais d’adreces:

  • Adreces físiques

    Utilitzades per hardware

  • Adreces virtuals

    Utilitzades pel software

La MMU (Memory Management Unit) és un component de hardware entre la CPU i la memòria que s’encarrega de traduir direccions virtuals a físiques, a més d’aplicar permisos d’accés i generar page faults quan la traducció no es vàlida segons les page tables.

La MMU opera sobre pages.

Abans de seguir és important conèixer el que són les pages i page frames:

  • Pages

    Unitat mínima de memòria (normalment 4KB)

  • Page frame

    Bloc real de memòria física, alineat i de mida de la page

El kernel té una estructura struct page per cada page frame físic, que conté flags (atributs) i un comptador de referències (quants processos tenen la page en ús).

La MMU utilitza una caché especial: el TLB (Translation Lookaside Buffer). Aquest TLB conté mapatges recents i permisos, és extremadament ràpid però també és limitat.

El procés per accedir a memòria és el següent:

  1. La CPU accedeix a una adreça virtual

  2. La MMU consulta el TLB

  3. Si la adreça virtual està al TLB, hi accedeix

  4. Si no hi és, la MMU la intenta buscar a les page tables

  5. Si no es pot accedir, genera una page fault

Una page fault és una excepció que es dona quan l’adreça no està mapejada, no hi ha prou permisos, la pàgina està swappejada o la pàgina encara no ha estat assignada.

No tots són errors, és part del funcionament normal del sistema.

Com hem comentat, el TLB és limitat, i això és un problema, ja que el kernel ha de conèixer tots els mapatges del sistema. Aquí és on entren en joc les page tables.

Al accedir a una adreça que no està al TLB, la MMU la busca per ls page tables i, si no hi pot accedir, llença una page fault i anirà a bucar-la a les page tables.

En x86_64, Linux té una jerarquia de 4 nivells (5 en sistemes més moderns) de page tables. Quan es genera una page fault, primer anirà al registre CR3 (conté l’adreça física del PGD del procés actual), i des d’allà:

PGD -> PUD -> PMD -> PTE

On aquests noms són els noms de les diferents page tables. Són una mena d’índexos on cada cop s’afina més la cerca.

També tenim el concepte de les huge pages, que són pàgines més grans que estalvien un o dos nivells de page tables, fent el procés més eficient.

El swapping és un procés que ens permet utilitzar memòria de disc com si fos RAM (amb certs matisos).

Quan falta memòria RAM:

  • El kernel copia un page frame a disc

  • La entrada del TLB s’invalida

  • El mapatge s’elimina de la page table

  • Reutilitza el frame físic que ha quedat lliure a RAM

I quan volem tornar a accedir a la memòria swapejada:

  • Page fault

  • Es bloqueja el procés

  • La pàgina en swap torna a RAM

  • Es remapeja

  • El procés continua

Tot i que la adreça física que tingui ara el page frame pugui haver canviat, la MMU s’encarregarà que la adreça virtual sigui la mateixa.

Quan un procés demana memòria, el kernel no la assigna immediatament, només crea el mapatge virtual i, quan calgui utilitzar la memòria, ja la assignarà.

Aquest procés s’anomena lazy allocation i redueix molt el consum de RAM i millora el rendiment del sistema.

Per aplicacions sensibles al temps d’operació, es poden pre-faultar pàgines amb mlock() i mlockall().

La gestió de memòria és un procés ben executat que dona a aquest sistema operatiu molt rendiment, escalabilitat, flexibilitat i seguretat.

Fins aquí el post d’avui, si tens alguna suggerència que podria mirar d’implementar per millorar el meu entorn, servidor o el que sigui, o simplement t’ha agradat el post, pots deixar un comentari i compartir. Bones festes i ens veiem al següent!