Monitorizarea memoriei pe Linux

Monitorizarea memoriei pe Linux

Diagnosticarea problemelor de memorie pe Linux poate fi frustrantă dacă nu știi ce unelte să folosești și ce înseamnă cifrele pe care le vezi. Același sistem poate părea că are memorie liberă din belșug sau că e la limită, în funcție de cum interpretezi datele. Acest articol acoperă toate uneltele importante pentru monitorizarea memoriei, de la comenzile de bază pe care le folosești zilnic până la analiza detaliată per proces.

free

free este prima comandă la care ajungi când vrei o imagine rapidă a memoriei. Rulezi întotdeauna cu -h pentru valori lizibile:

free -h
               total        used        free      shared  buff/cache   available
Mem:            15Gi       4.2Gi       6.1Gi       412Mi       5.1Gi        10Gi
Swap:          2.0Gi       128Mi       1.9Gi

Coloana care contează cu adevărat este available - nu free. Iată de ce:

free arată memoria complet neutilizată, fără niciun conținut. Pare mic pentru că Linux folosește RAM-ul liber ca cache de disc - un comportament normal și de dorit.

buff/cache este memoria folosită de kernel pentru buffere I/O și cache de pagini. Această memorie poate fi eliberată imediat dacă un proces are nevoie - kernelul o sacrifică fără probleme.

available este suma dintre free și partea din buff/cache care poate fi eliberată imediat. Aceasta este memoria reală disponibilă pentru procese noi fără a folosi swap. Dacă available se apropie de zero, sistemul e sub presiune reală de memorie.

shared este memoria partajată între procese, inclusiv tmpfs (/dev/shm, /run).

Urmărești evoluția în timp cu:

watch -n 2 free -h

/proc/meminfo

/proc/meminfo este sursa de date pentru toate celelalte unelte - free, htop și altele citesc de aici. Conține zeci de câmpuri, dar cele mai relevante sunt:

cat /proc/meminfo
MemTotal:       16248832 kB   # RAM fizic total
MemFree:         6291456 kB   # RAM complet liber
MemAvailable:   10485760 kB   # RAM disponibil pentru procese noi
Buffers:          524288 kB   # Buffer cache pentru metadata de disc
Cached:          4718592 kB   # Page cache (conținut fișiere)
SwapCached:        32768 kB   # Pagini aduse din swap, încă în swap
Active:          5242880 kB   # Pagini accesate recent
Inactive:        3145728 kB   # Pagini candidate pentru swap/eliberare
Active(anon):    2097152 kB   # Pagini anonime active (heap, stack)
Inactive(anon):  1048576 kB   # Pagini anonime inactive
Active(file):    3145728 kB   # Cache de fișiere accesate recent
Inactive(file):  2097152 kB   # Cache de fișiere accesate mai demult
SwapTotal:       2097152 kB   # Swap total
SwapFree:        1966080 kB   # Swap disponibil
Dirty:             16384 kB   # Pagini modificate, neîncă scrise pe disc
Writeback:             0 kB   # Pagini în curs de scriere pe disc
AnonPages:       3145728 kB   # Total pagini anonime mapate
Mapped:           524288 kB   # Fișiere mapate în memorie (mmap)
Shmem:            425984 kB   # Memorie partajată și tmpfs
Slab:             786432 kB   # Cache-uri interne ale kernelului
SReclaimable:     524288 kB   # Slab care poate fi eliberat
SUnreclaim:       262144 kB   # Slab care nu poate fi eliberat
HugePages_Total:       0      # Huge Pages rezervate
HugePages_Free:        0      # Huge Pages disponibile
AnonHugePages:    614400 kB   # Memorie anonimă în THP

Câteva valori care merită atenție specială:

Dirty - pagini modificate în memorie care nu au fost încă scrise pe disc. O valoare constant mare poate indica un sistem care scrie mult pe disc și e limitat de I/O.

Slab - memoria folosită de kernelul însuși pentru structuri interne (inode cache, dentry cache, etc.). Pe serverele de fișiere sau cu multe procese, Slab poate ajunge la sute de MB sau chiar GB. SReclaimable e partea care poate fi eliberată sub presiune.

SwapCached - pagini care au fost aduse din swap înapoi în RAM, dar care există și în swap. Dacă procesul le accesează din nou, nu mai trebuie citite de pe disc. O valoare pozitivă indică faptul că sistemul a swap-at recent.

vmstat

vmstat oferă o vedere de ansamblu a sistemului: memorie, swap, I/O, procesor - totul într-o singură linie. Este ideal pentru monitorizarea în timp real a presiunii pe memorie:

vmstat 2 10

Afișează 10 linii la interval de 2 secunde. Prima linie conține medii de la pornire și se ignoră de obicei.

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 131072 6291456 524288 4718592  0    0     12    48  245  512  5  2 92  1  0
 0  0 131072 6287360 524288 4722688  0    0      0    16  198  423  2  1 97  0  0

Coloanele critice pentru memorie și swap:

swpd - cantitatea totală de swap folosit în KB. Dacă crește constant, sistemul e sub presiune.

free - RAM liber în KB (nu include buff/cache).

si (swap in) - pagini aduse din swap în RAM pe secundă. Valori constant diferite de zero indică un sistem care lucrează cu date paginate.

so (swap out) - pagini trimise din RAM în swap pe secundă. Dacă so e constant pozitiv, kernelul paginează activ și performanța suferă.

bi/bo - blocuri citite/scrise pe disc pe secundă. Valori mari corelate cu si/so confirmă că swap-ul pe disc e activ.

Pentru o sesiune de monitorizare mai lungă, redirecționezi output-ul:

vmstat 5 > /tmp/vmstat_log.txt &

htop

htop este monitorul interactiv cel mai folosit pe Linux și afișează informații despre memorie atât la nivel de sistem cât și per proces. Barele din partea de sus arată RAM-ul și swap-ul, cu coduri de culoare:

  • Verde - memorie folosită de procese
  • Albastru - buffer cache
  • Galben/Portocaliu - cache de pagini
  • Roșu - swap folosit

Coloanele relevante pentru memorie în lista de procese sunt RES (memoria fizică reală folosită de proces, fără pagini partajate) și VIRT (spațiul virtual total alocat, irelevant pentru consumul real).

Poți filtra după consum de memorie apăsând F6 și selectând MEM%. Pentru a vedea swap-ul per proces, adaugi coloana SWAP prin F2 → Columns.

ps

ps este util pentru snapshots rapide ale consumului de memorie per proces. Afișezi procesele sortate după consum de RAM:

ps aux --sort=-%mem | head -20

sau cu mai multe detalii:

ps -eo pid,ppid,cmd,%mem,%cpu,rss,vsz --sort=-%mem | head -20

RSS în output-ul ps este în KB și reprezintă memoria fizică ocupată, incluzând paginile partajate - poate supraestima consumul real dacă procesul folosește multe biblioteci partajate.

smem

smem este unealta cea mai precisă pentru analiza consumului de memorie per proces, deoarece calculează PSS (Proportional Set Size) - memoria partajată este împărțită proporțional între procesele care o folosesc, oferind o imagine realistă a consumului real.

Instalezi:

# Ubuntu/Debian
apt install smem
 
# Fedora
dnf install smem
 
# Arch Linux
pacman -S smem

Afișezi procesele sortate după PSS:

smem -rs pss | head -20

Afișezi consumul total per utilizator:

smem -u

Afișezi consumul per program (agregate toate instanțele):

smem -P nginx -r

Un raport complet cu toate metricile:

smem -r -k

-k afișează valorile în KB/MB/GB în loc de bytes brute.

pmap

pmap arată harta de memorie detaliată a unui singur proces - fiecare zonă de memorie mapată, cu dimensiunea și permisiunile ei:

pmap -x PID
Address           Kbytes     RSS   Dirty Mode  Mapping
0000563f2a000000    2048    1024       0 r-x-- nginx
0000563f2a200000     256     256     256 r---- nginx
0000563f2a240000      64      64      64 rw--- nginx
00007f8b4c000000   51200   32768   32768 rw---   [ anon ]
00007f8b4f000000  131072       0       0 -----   [ anon ]
...

Coloanele importante sunt RSS (memoria fizică efectiv ocupată) și Dirty (pagini modificate față de versiunea de pe disc). Zonele marcate anon sunt heap sau memorie anonimă (malloc), cele cu nume de fișiere sunt biblioteci sau fișiere mapate.

Pentru un sumar rapid:

pmap -x PID | tail -1

Ultima linie conține totalurile. Util pentru a verifica rapid cât ocupă un proces fără a parcurge toată lista.

/proc/PID/smaps

/proc/PID/smaps conține informațiile cele mai detaliate despre memoria unui proces, câmpuri pentru fiecare zonă mapată. Este sursa de date pentru smem și pmap. Pentru un sumar rapid al câmpurilor agregate:

cat /proc/PID/smaps_rollup
Rss:              45678 kB
Pss:              12345 kB
Pss_Anon:          8192 kB
Pss_File:          4096 kB
Pss_Shmem:           57 kB
Shared_Clean:     32768 kB
Shared_Dirty:         0 kB
Private_Clean:     1024 kB
Private_Dirty:     7168 kB
Referenced:       45678 kB
Anonymous:         8192 kB
AnonHugePages:     4096 kB
Swap:              2048 kB
SwapPss:           1024 kB

Swap arată exact câtă memorie a acestui proces e în swap în momentul citirii. SwapPss e varianta proporțională pentru paginile de swap partajate.

Pentru a vedea toate procesele cu swap, sortate:

for pid in /proc/[0-9]*/smaps_rollup; do
  p=$(dirname $pid | xargs basename)
  swap=$(awk '/^Swap:/{print $2}' $pid 2>/dev/null)
  name=$(cat /proc/$p/comm 2>/dev/null)
  echo "$swap $p $name"
done | sort -rn | awk '$1>0' | head -20

slabtop

Cache-ul Slab al kernelului poate consuma cantități semnificative de RAM pe servere active, fără să apară în statisticile per proces. slabtop este htop-ul pentru cache-urile interne ale kernelului:

slabtop

Sau un snapshot non-interactiv:

slabtop -o | head -30

Cache-urile frecvent mari:

  • dentry - cache pentru intrările de director, crește pe sisteme cu multe fișiere
  • inode_cache - cache pentru inoduri de fișiere
  • ext4_inode_cache sau similar - specific sistemului de fișiere
  • kmalloc-* - alocări generale ale kernelului

Pe un server cu NFS sau cu multe fișiere deschise simultan, dentry și inode cache pot ajunge la câțiva GB. Sunt eliberate automat sub presiune de memorie (fac parte din SReclaimable).

Poți elibera manual cache-urile Slab (util pentru testare, nu pentru producție):

echo 2 > /proc/sys/vm/drop_caches   # eliberează dentry și inode cache
echo 3 > /proc/sys/vm/drop_caches   # eliberează page cache, dentry și inode

Pe producție, această comandă poate degrada temporar performanța - kernelul va trebui să reconstruiască cache-urile din disc.

sar

sar (System Activity Reporter) face parte din pachetul sysstat și colectează statistici de sistem la intervale regulate, stocându-le pentru analiză ulterioară. Ideal pentru a înțelege ce s-a întâmplat cu memoria ieri noapte sau săptămâna trecută.

Instalezi și activezi colectarea:

# Ubuntu/Debian
apt install sysstat
systemctl enable --now sysstat
 
# Fedora
dnf install sysstat
systemctl enable --now sysstat

Raport de memorie pentru ziua curentă:

sar -r

Raport pentru o zi specifică (datele sunt salvate în /var/log/sa/):

sar -r -f /var/log/sa/sa17   # ziua 17 a lunii curente

Urmărești swap-ul în timp:

sar -W

Coloanele pswpin/s și pswpout/s arată paginile swap-ate per secundă - echivalentul si/so din vmstat, dar cu istoric.

Scenarii practice de diagnosticare

Sistemul e lent - e vina memoriei?

# Verifici rapid disponibilul
free -h
 
# Confirmi cu vmstat - cauți si/so diferite de zero
vmstat 2 5
 
# Identifici procesele mari
ps aux --sort=-%mem | head -10

Dacă available e sub 500MB și so e constant pozitiv, confirmi problema de memorie. Dacă available e rezonabil și so e zero, problema e probabil altundeva (CPU, I/O, rețea).

Un serviciu consumă prea mult RAM

# Găsești PID-ul
pgrep -f nume_serviciu
 
# Verifici consumul real (PSS)
cat /proc/PID/smaps_rollup | grep Pss
 
# Sau cu smem
smem -P nume_serviciu -r

Swap-ul a crescut brusc

# Găsești ce e în swap
for pid in /proc/[0-9]*/smaps_rollup; do
  p=$(dirname $pid | xargs basename)
  swap=$(awk '/^Swap:/{print $2}' $pid 2>/dev/null)
  name=$(cat /proc/$p/comm 2>/dev/null)
  echo "$swap $p $name"
done | sort -rn | awk '$1>0' | head -10
 
# Verifici când s-a întâmplat
journalctl -k | grep -i "oom\|memory"

Slab consumă mult

# Verifici totalul
grep Slab /proc/meminfo
 
# Identifici cache-urile mari
slabtop -o | head -20

Resurse suplimentare