Linux e RAM

Negli ultimi anni il tema della memoria RAM è tornato centrale. Container ovunque, Kubernetes, VM leggere, database in-memory, AI locale e workload sempre più aggressivi hanno cambiato completamente il modo in cui i sistemi Linux utilizzano la memoria.
Eppure c’è una situazione che continua a terrorizzare chi amministra server:
$ free -h
e quel famigerato:
RAM usage: 99%
La prima reazione è quasi sempre la stessa:
“Qualcosa sta saturando il server.”
In realtà, molto spesso, Linux sta semplicemente facendo il suo lavoro.
Uno degli aspetti più affascinanti del kernel Linux è proprio il modo in cui tratta la memoria: non come una risorsa da conservare, ma come una risorsa da sfruttare fino all’ultimo byte disponibile.
In questo articolo vediamo come Linux gestisce davvero la RAM, perché “memoria piena” non significa automaticamente “problema”, e quali strumenti usare per capire quando il sistema è realmente sotto pressione.
La RAM inutilizzata è RAM sprecata
Questo è il primo concetto fondamentale da capire.
Linux cerca costantemente di utilizzare tutta la memoria disponibile per migliorare le performance del sistema.
Se un server ha:
- 32 GB di RAM
- applicazioni che ne usano solo 12 GB
il kernel userà la memoria restante per:
- page cache
- buffer filesystem
- inode cache
- dentries cache
- read-ahead
Tutto questo serve a ridurre l’I/O disco e velocizzare l’accesso ai dati.
Ed è qui che nasce il classico equivoco:
used != realmente occupata
Guardiamo ad esempio l’output moderno di free:
free -h
total used free shared buff/cache available
Mem: 31Gi 28Gi 512Mi 1.2Gi 18Gi 19Gi
A prima vista sembra un sistema quasi saturo.
In realtà:
- 18 GB sono cache liberabile
- 19 GB sono immediatamente disponibili
Il parametro davvero importante oggi è:
available
non free.
Come Linux vede la memoria
Linux non consegna mai direttamente la RAM fisica ai processi.
Ogni processo vive dentro uno spazio virtuale chiamato:
Virtual Address Space (VAS)
Questo permette due cose fondamentali:
Isolamento
Ogni processo vede la propria memoria privata.
Un processo non può leggere o modificare la memoria di un altro processo senza permessi espliciti.
Astrazione
Il programma pensa di avere memoria continua, ma fisicamente i dati possono trovarsi:
- in RAM
- in swap
- in page cache
- sparse in zone completamente diverse della memoria fisica
È il kernel che si occupa di tradurre tutto questo.
Virtual memory: la vera magia di Linux
La virtual memory è probabilmente uno dei meccanismi più importanti dell’intero sistema operativo.
Un processo può allocare più memoria della RAM fisica realmente disponibile.
Sembra assurdo, ma funziona grazie a:
- paging
- swap
- demand paging
- overcommit
Un esempio molto semplice:
- server con 8 GB di RAM
- processi che allocano 20 GB virtuali
Linux permette comunque l’esecuzione perché sa che:
- non tutta la memoria verrà usata contemporaneamente
- parte finirà in swap
- molte pagine resteranno mai utilizzate
Pagine e Page Table
La memoria viene suddivisa in blocchi chiamati:
pages
Tipicamente:
4 KB
Ogni processo usa pagine virtuali.
La RAM reale invece è composta da:
page frames
Il kernel mantiene una gigantesca struttura chiamata:
Page Table
che dice:
“La pagina virtuale X corrisponde al frame fisico Y.”
Questa traduzione viene fatta continuamente dalla MMU (Memory Management Unit) della CPU.
Page Fault: quando il kernel interviene
Uno dei termini più fraintesi è:
page fault
Non è automaticamente un errore.
Anzi, spesso è comportamento assolutamente normale.
Esistono due tipi principali.
Minor Page Fault
La pagina è già presente in RAM.
Serve solo aggiornare le strutture interne del processo.
Costo minimo.
Major Page Fault
La pagina non è in RAM.
Il kernel deve recuperarla:
- da disco
- da swap
- da file mapping
Questo è molto più costoso.
Se i major fault aumentano continuamente, il sistema inizia a rallentare pesantemente.
Monitoraggio rapido:
sar -B 1
oppure:
vmstat 1
Il Page Cache: il vero utilizzatore della RAM
Il page cache è probabilmente il motivo principale per cui Linux mostra RAM quasi piena.
Quando un file viene letto:
- il kernel lo carica dal disco
- lo consegna all’applicazione
- ne mantiene una copia in RAM
Se il file viene richiesto nuovamente:
- niente accesso disco
- lettura immediata dalla RAM
Prestazioni enormemente superiori.
Free RAM is wasted RAM
È una filosofia precisa del kernel Linux.
RAM libera significa:
- risorsa inutilizzata
- opportunità persa per velocizzare il sistema
Per questo Linux riempie aggressivamente la memoria con cache filesystem.
Ma attenzione:
questa memoria è “prestata”.
Quando un’applicazione ha bisogno di RAM:
- il cache viene ridotto
- le pagine meno usate vengono eliminate
- la memoria torna disponibile
Il tutto in modo automatico.
Dirty Pages e Writeback
Quando scriviamo un file, spesso i dati non finiscono immediatamente sul disco.
Prima vengono salvati nel page cache come:
dirty pages
Successivamente thread del kernel come:
kworker
si occupano del:
writeback
ovvero della scrittura reale sul filesystem.
Questo migliora drasticamente le performance di scrittura.
Ed è esattamente il motivo per cui rimuovere brutalmente una chiavetta USB può corrompere i dati.
Swap: davvero serve ancora?
Domanda eterna.
Molti oggi disabilitano completamente lo swap.
Personalmente lo considero ancora estremamente utile.
Non tanto come “RAM extra”, ma come:
- buffer di emergenza
- meccanismo di stabilizzazione
- protezione contro OOM immediati
Linux usa lo swap principalmente per spostare fuori dalla RAM:
- pagine inattive
- dati poco usati
- processi dormienti
Questo libera RAM per:
- page cache
- workload attivi
- filesystem cache
Lo swappiness
Il comportamento dello swap è regolato da:
cat /proc/sys/vm/swappiness
Valori tipici:
| Valore | Comportamento |
|---|---|
| 0-10 | swap quasi evitato |
| 60 | default Linux |
| 100 | swap aggressivo |
Su server moderni spesso si usa:
10
oppure:
1
ma dipende fortemente dal workload.
Thrashing: il vero nemico
Il problema reale non è “RAM piena”.
Il problema è:
thrashing
ovvero quando il sistema passa il tempo a:
- swap-in
- swap-out
- reclaim continuo
- major page fault continui
Sintomi tipici:
- load average altissimo
- CPU apparentemente “idle”
- disco al 100%
- sistema congelato
Qui il collo di bottiglia diventa l’I/O.
PSI: il parametro che pochi monitorano
Una delle feature più interessanti introdotte nei kernel moderni è:
Pressure Stall Information
Disponibile in:
cat /proc/pressure/memory
Questo parametro misura quanto tempo i processi passano bloccati in attesa di memoria.
È molto più utile della semplice percentuale RAM usata.
Perché un sistema può avere:
- 99% RAM usata
- zero pressione reale
oppure:
- 60% RAM usata
- pressione elevatissima
OOM Killer: l’ultima linea di difesa
Quando:
- RAM finisce
- swap finisce
- reclaim non basta
entra in gioco:
OOM Killer
Il kernel sceglie un processo da terminare per salvare il sistema.
La scelta avviene in base a:
- memoria consumata
- priorità
- tipo di processo
- oom_score
Verifica:
cat /proc/<pid>/oom_score
Controllo log:
dmesg | grep -i oom
oppure:
journalctl -xe | grep -i oom
Container e memoria: il nuovo scenario moderno
Con Docker e Kubernetes il discorso cambia parecchio.
Qui entrano in gioco i:
cgroups
che permettono di limitare memoria per:
- container
- servizi
- processi
Esempio con systemd:
systemctl set-property myapp.service MemoryMax=1G
Oppure con Docker:
docker run -m 1g nginx
Quando il container supera il limite:
- il kernel attiva OOM localizzato
- il container viene terminato
- l’host continua a funzionare
È uno dei motivi principali per cui i container “muoiono improvvisamente”.
Come capire se la RAM è davvero un problema
Le metriche che guardo realmente in produzione sono:
1. PSI
cat /proc/pressure/memory
2. Major Page Fault
sar -B
3. Swap activity
vmstat 1
che aggiorna le statistiche ogni secondo.
Un output tipico:
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 524288 320000 180000 8200000 0 0 1 2 120 300 2 1 96 0 0
Le colonne che interessano davvero quando si analizza la memoria sono:
| Colonna | Significato |
|---|---|
| si | Swap In |
| so | Swap Out |
so — Swap Out
Indica quanta memoria il kernel sta spostando:
RAM → swap
si — Swap In
Questa è la colonna molto più critica.
Indica quanta memoria viene riportata:
swap → RAM
Il problema reale: il disco
La RAM lavora in nanosecondi.
Lo swap lavora in:
- microsecondi su NVMe
- millisecondi su SSD/SATA
La differenza è enorme.
Quando il kernel entra in thrashing:
- la CPU resta idle
- il load average sale
- il sistema sembra “freezato”
perché tutto il tempo viene speso aspettando I/O.
vm.vfs_cache_pressure
Un parametro poco conosciuto ma estremamente importante nella gestione memoria è:
cat /proc/sys/vm/vfs_cache_pressure
Questo valore controlla quanto aggressivamente il kernel recupera memoria dalle cache VFS.
In pratica decide quanto velocemente Linux libera:
- inode cache
- dentry cache
- metadata filesystem
per recuperare RAM.
4. Cache reclaim aggressivo
cat /proc/vmstat
5. OOM events
dmesg
Conclusione
La gestione della memoria in Linux è uno degli aspetti più sofisticati dell’intero sistema operativo.
E soprattutto:
RAM piena non significa necessariamente sistema sotto stress.
Molto spesso significa esattamente il contrario:
- cache efficiente
- filesystem ottimizzato
- I/O ridotto
- performance migliori
I veri segnali da monitorare oggi sono:
- memory pressure
- major fault
- swap thrashing
- reclaim aggressivo
- OOM event
Capire questi meccanismi cambia completamente il modo di leggere un server Linux.
Ed è probabilmente una delle differenze più grandi tra “guardare htop” e capire davvero cosa sta facendo il kernel.
Le opinioni in quanto tali sono opinabili e nulla ti vieta di approfondire l’argomento.
Risorse: