Mão na massa · ~48 min
Lendo a memória de verdade — e provocando um OOM
Hoje você aprende a ler os números certos da memória (o campo que importa não é o que a maioria olha), localiza os maiores consumidores do sistema, e fecha provocando de propósito a morte de um container por falta de memória.
Passo 1 de 7
A visão geral da memória
free -hO que é
Mostra memória total, usada, livre, em cache e disponível. O -h converte pra unidades legíveis (Gi, Mi) em vez de bytes.
Por que importa
É a primeira resposta pra "a máquina está sem memória?" — desde que você olhe a coluna certa.
$ free -h total used free shared buff/cache available Mem: 3.8Gi 1.2Gi 0.4Gi 12Mi 2.2Gi 2.3Gi Swap: 2.0Gi 0B 2.0Gi
repare que free (livre) parece baixo, mas available (disponível) está alto. Isso é normal e desejável — o Linux usa memória ociosa como cache de disco e devolve assim que alguém precisar.
Então qual coluna eu devo olhar?
available. É quanto realmente dá pra alocar agora sem recorrer a swap. A coluna used sozinha engana, e free quase sempre parece assustadoramente baixa num sistema saudável.
na sua VM, qual a diferença entre os valores de "free" e "available"? Por que essa diferença existe?
0 / 40 caracteres
Passo 2 de 7
A versão crua, direto do kernel
/proc.head -8 /proc/meminfoO que é
O arquivo que o free lê por baixo dos panos. Tem dezenas de campos; as primeiras linhas já trazem o essencial.
Por que importa
Confirma que não há mágica: MemAvailable aqui é exatamente a coluna available do passo anterior.
$ head -8 /proc/meminfo MemTotal: 3986432 kB MemFree: 438292 kB MemAvailable: 2405118 kB Buffers: 83104 kB Cached: 1912440 kB
os valores em kB. Divida por 1024 duas vezes pra chegar em GB e conferir que bate com o free -h do passo 1.
Passo 3 de 7
Quem está consumindo mais
ps aux --sort=-%mem | head -6O que é
--sort=-%mem ordena a lista por percentual de memória, do maior pro menor. O head -6 pega o cabeçalho + os 5 maiores.
Por que importa
É exatamente assim que se identifica o candidato a vazamento numa máquina de produção.
$ ps aux --sort=-%mem | head -6 USER PID %CPU %MEM VSZ RSS TTY STAT COMMAND aluno 2417 0.3 4.2 2841096 167284 ? Sl /usr/lib/firefox/firefox aluno 1804 0.8 3.9 4105216 158920 ? Ssl /usr/bin/gnome-shell root 891 0.0 1.1 1534208 44120 ? Ssl /usr/lib/snapd/snapd aluno 1930 0.0 0.3 11520 5236 pts/0 Ss bash
a coluna RSS (Resident Set Size), em kB, é a memória física ocupada por aquele processo; VSZ é o espaço de endereçamento reservado. RSS é o número a comparar entre processos. Anote o PID do maior, você vai usá-lo no próximo passo.
Passo 4 de 7
A memória de um processo específico
grep Vm /proc/<PID>/statusO que é
Filtra os campos de memória virtual daquele processo. Troque <PID> pelo número que você anotou.
Por que importa
VmRSS é a memória física de verdade; VmSize é o espaço de endereçamento reservado — quase sempre bem maior, e isso é normal.
$ grep Vm /proc/2417/status VmSize: 2841096 kB VmRSS: 167284 kB VmData: 712408 kB VmStk: 132 kB
VmSize muito maior que VmRSS. Isso é o espaço de endereçamento do slide 3 em ação — o processo "reservou" muito mais do que realmente está usando na RAM.
Deu "Arquivo ou diretório inexistente"
O processo pode ter terminado entre o passo 3 e o 4. Rode o ps aux --sort=-%mem | head -6 de novo e use um PID atualizado.
Passo 5 de 7
Um container com limite apertado
docker run -d --name memtest --memory=64m --memory-swap=64m alpine sh -c "cat /dev/zero | head -c 500m | tail"O que é
--memory=64m limita o container a 64 MB de RAM, e --memory-swap=64m (o mesmo valor) proíbe o uso de swap além disso. O comando interno tenta acumular 500 MB na memória: o tail guarda tudo, porque espera uma quebra de linha que /dev/zero nunca manda.
Por que importa
Reproduz, de forma controlada e segura, exatamente o cenário que derruba serviços em produção.
$ docker run -d --name memtest --memory=64m --memory-swap=64m alpine sh -c "cat /dev/zero | head -c 500m | tail" b7e2a90c4f13d8a5...
Importante
⚠️ Importante: mantenha os dois limites. São eles que garantem que o estrago fique contido dentro do container — sem eles, esse mesmo comando pode travar sua VM inteira.
Por que também o --memory-swap?
Com só --memory=64m, o Docker deixa o container usar mais 64 MB de swap. O container não morre ao bater nos 64 MB: primeiro fica lento, jogando memória para o disco. Igualar os dois valores faz o teto ser de 64 MB mesmo, e o OOM acontecer na hora.
Passo 6 de 7
Confirmando a morte por OOM
docker ps -a --filter name=memtestO que é
-a mostra também containers já encerrados — necessário aqui, porque o nosso deve ter morrido.
Por que importa
O código de saída 137 (128 + 9) quer dizer "morto com SIGKILL", o sinal que o OOM Killer usa. Junto com OOMKilled: true, é a assinatura de morte por falta de memória — reconhecê-la é competência direta de sustentação.
$ docker ps -a --filter name=memtest NAME IMAGE STATUS memtest alpine Exited (137) 4 seconds ago
Exited (137). Confirme com docker inspect memtest --format '{{.State.OOMKilled}}' — deve retornar true. O 137 sozinho não basta: um docker kill também dá 137, mas com OOMKilled falso.
Meu container terminou com código 0, sem OOM
Quase sempre é o swap: confira se você digitou o --memory-swap=64m no passo 5. Remova o container (docker rm memtest) e repita o passo 5 com os dois limites.
o que aconteceu com o container memtest e por quê? O que o código de saída 137 indica?
0 / 40 caracteres
Passo 7 de 7
Limpando
docker rm memtestO que é
Remove o registro do container já encerrado (não precisa de docker stop — ele já morreu sozinho).
Por que importa
Containers encerrados continuam ocupando espaço em disco até serem removidos.
o nome memtest impresso de volta, confirmando a remoção.
livre: algo que te surpreendeu ou uma dúvida que sobrou de hoje
0 / 40 caracteres
Exemplo de observação forte × fraca
Observação fraca
"O container morreu porque ficou sem memória."
Observação forte
"O container saiu com código 137 e OOMKilled: true. Ele tentou acumular 500 MB, mas o --memory=64m, sem swap extra, impôs um teto de 64 MB; ao ultrapassá-lo, o kernel matou o processo com SIGKILL, sem chance de salvar estado. O importante é que o estrago ficou contido: a VM continuou funcionando normalmente, porque o limite isolou o problema naquele container."
Checklist final
- Rodei
free -he identifiquei a diferença entrefreeeavailable - Conferi que o
/proc/meminfobate com ofree - Listei os 5 maiores consumidores de memória e anotei um PID
- Comparei
VmSizecomVmRSSde um processo - Subi um container com
--memory=64me provoquei o OOM - Confirmei o
Exited (137)/OOMKilled: true - Removi o container de teste
- Preenchi as 3 observações acima (vou colar no quiz semanal)