28 out 2026 · linux, memória, processos · 4 min
Como medir a memória de um processo de verdade?
RSS conta páginas residentes, VSZ conta espaço de endereços, e nenhum dos dois é o que o cgroup cobra. Para saber o custo real de um processo, leia PSS em /proc/PID/smaps_rollup e memory.current no cgroup dele. Top e htop mostram RSS, que conta bibliotecas compartilhadas várias vezes e ignora cache de página.
O erro mais comum ao olhar para um processo é tratar RES do top como “memória usada”. RES é RSS: páginas do processo que estão na RAM neste momento. Ele não diz quem compartilha essas páginas, não conta o cache que o kernel guarda para esse processo, e não diz se o espaço de endereços está só reservado ou de fato ocupado.
O que cada número mede
| Métrica | Onde ler | O que conta | Quando olhar |
|---|---|---|---|
| VmSize / VSZ | /proc/PID/status ou statm | Espaço de endereços mapeado, incluindo o que só foi reservado | Só para saber o teto teórico |
| VmRSS / RSS | /proc/PID/status ou statm | Páginas residentes na RAM, compartilhadas contadas inteiras para cada processo | Visão rápida no top |
| PSS | /proc/PID/smaps_rollup | RSS dividido entre os processos que compartilham a página | Memória real atribuível |
| USS | soma de Private_* no smaps_rollup | Páginas privadas do processo, sem compartilhamento | Quanto libera se matar o processo |
| memory.current | /sys/fs/cgroup/…/memory.current | RSS + cache + memória de kernel do cgroup inteiro | O que o orçamento do contêiner mede |
O que o cgroup cobra
O cgroup é a unidade que o kernel usa para cobrar memória de um contêiner ou de um serviço. memory.current inclui o RSS do processo, o cache de página atribuído a esse cgroup e um pouco de memória de kernel. É por isso que um contêiner com limite de 256 MB pode ser morto pelo OOM killer mesmo com RSS de 200 MB: o cache conta.
Se o processo roda no host, sem cgroup próprio, memory.current do cgroup do usuário mistura tudo, e a leitura perde o sentido. Rode o processo isolado, num contêiner ou numa unidade systemd com MemoryMax, para a conta fechar.
Artefato: medir um processo em 30 segundos
O script abaixo mede um PID que você passar ou, sem argumento, cria um filho que aloca 32 MiB e mede ele. Ele lê /proc, smaps_rollup e o cgroup do processo, e imprime os cinco números lado a lado.
#!/usr/bin/env bash
set -euo pipefail
ALLOC_MB="${ALLOC_MB:-32}"
DUR="${DUR:-4}"
PAGINA="$(getconf PAGESIZE 2>/dev/null || echo 4096)"
medir() {
local pid="$1"
echo "=== PID $pid ==="
if [ ! -d "/proc/$pid" ]; then
echo "processo nao existe"; return 1
fi
echo "-- /proc/$pid/status --"
grep -E '^(Name|VmSize|VmRSS|VmHWM|VmSwap|Threads):' "/proc/$pid/status" || true
echo "-- /proc/$pid/statm (pages of $PAGINA bytes) --"
cat "/proc/$pid/statm"
echo "-- smaps_rollup --"
grep -E '^(Rss|Pss|Shared_Clean|Private_Clean|Shared_Dirty|Private_Dirty|Anonymous|Swap|Locked):' "/proc/$pid/smaps_rollup" 2>/dev/null || echo "(sem smaps_rollup)"
echo "-- cgroup --"
local cg
cg="$(sed -n 's/^0:://p' /proc/$pid/cgroup 2>/dev/null)"
echo "cgroup path: ${cg:-?}"
if [ -n "$cg" ] && [ -f "/sys/fs/cgroup${cg}/memory.current" ]; then
echo "memory.current: $(cat /sys/fs/cgroup${cg}/memory.current) bytes"
echo "memory.max: $(cat /sys/fs/cgroup${cg}/memory.max 2>/dev/null || echo ?)"
echo "memory.stat rss/cache:"
grep -E '^(rss|cache|anon|kernel) ' "/sys/fs/cgroup${cg}/memory.stat" 2>/dev/null || true
fi
echo "-- ps --"
ps -o pid,vsz,rss,%mem,comm -p "$pid" 2>/dev/null || true
}
if [ $# -ge 1 ] && [ -n "${1:-}" ]; then
medir "$1"
exit 0
fi
echo "Alocando ${ALLOC_MB} MiB num processo filho e medindo..."
(
x=$(head -c $((ALLOC_MB*1024*1024)) /dev/zero | tr '\0' 'A')
: "${x:0:1}"
sleep "$DUR"
) &
child=$!
trap 'kill "$child" 2>/dev/null || true; wait "$child" 2>/dev/null || true' EXIT
sleep 1
medir "$child"
echo
echo "Legenda: VSZ = espaco de enderecos; RSS = paginas residentes; PSS divide compartilhado; cgroup memory.current inclui cache do processo."
Salve como mede-memoria.sh, torne executável com chmod +x mede-memoria.sh.
Como verificar
Rode ALLOC_MB=32 ./mede-memoria.sh. A saída deve ter VmRSS entre 90 e 110 MiB (o bash que segura a string de 32 MiB tem overhead próprio) e memory.current entre 95 e 120 MiB. Se memory.current for maior que VmRSS, a diferença é cache e memória de kernel do cgroup.
Se der errado
processo nao existe: o filho terminou antes da leitura. Aumente DUR (DUR=8 ./mede-memoria.sh) ou meça um PID de longa vida.sem smaps_rollup: kernel sem suporte (anterior a 4.14) ou /proc montado com hidepid. Usepmap -x PIDou leia /proc/PID/smaps.memory.currentmuito maior que VmRSS: o cgroup contém outros processos ou cache. Isole o processo num contêiner com--memoryou numa unidade systemd.Permission deniedlendo /proc/PID: processo de outro usuário. Rode como o mesmo usuário ou como root.
Qual usar quando
Se você quer entender por que o limite do contêiner é em cgroup, leia O que são cgroups. Se o problema é descobrir quem está consumindo memória no host, Como ver o que está comendo a memória no Linux. Para limitar um contêiner de propósito, Como limitar memória, log e reinício de um contêiner.
FAQ
RSS e “memória usada” são a mesma coisa? Não. RSS conta páginas residentes, incluindo compartilhadas; não conta cache por processo; não diz se o espaço está reservado ou usado.
Por que VSZ é tão grande? É o espaço de endereços reservado por mmap e malloc. Não é RAM.
PSS ou USS para decidir se mato um processo? USS diz o que libera. PSS é melhor para comparar processos que compartilham bibliotecas.
Top não basta? Top é bom para achar o suspeito. Para cobrar custo, use o cgroup.
Como medir um contêiner inteiro? Leia memory.current do cgroup do contêiner. É a conta que o kernel usa para aplicar o limite.
Fontes
- proc(5), consultado em 28 out 2026.
- cgroups(7), consultado em 28 out 2026.
- Control Group v2, consultado em 28 out 2026.