VM lenta? Auditando CPU, RAM e um .bashrc que corrompe sozinho
Como auditei uma VM Oracle Cloud que travava e encontrei um .bashrc corrompido enchendo a memória — diagnóstico por evidência, não por palpite.
O problema
A VM Oracle Cloud (ARM, gratis-tier) tinha dias em que ficava lenta sem motivo aparente. SSH demorava pra conectar, comandos travavam, às vezes o claude respondia com atraso de 30 segundos antes de qualquer coisa. Reiniciar resolvia — temporariamente. Eu ficava na dúvida: era a VM sendo fraca? Era o processo do LiteLLM? Era a rede? Tailscale?
O problema de “está lento” como sintoma é que ele não te aponta causa nenhuma. Você precisa medir pra descobrir. E nessa sessão de auditoria, descobri duas coisas: a CPU não era o gargalo (surpresa), e tinha um .bashrc com loop de função recursiva que tava comendo RAM aos poucos, todo login.
Esse artigo é o passo a passo de como cheguei lá, na ordem que executei — porque a ordem importa pra não se perder.
Passo 1: o que está consumindo, agora
Antes de palpite, medição. O comando mais honesto de diagnóstico em Linux:
top -b -n 1 | head -20
Ou, mais legível, htop se estiver instalado. O que eu procurava: qual processo está no topo da lista de CPU e de memória. Na minha VM, surpresa: o node (Claude Code) e o litellm estavam razoáveis. Mas tinha um processo bash consumindo 18% de RAM — estranho pra um shell que não deveria fazer nada.
ps aux --sort=-%mem | head -10
Ordenado por memória, vi claramente: dois processos bash ocupando espaço desproporcional. Um deles era o shell do meu SSH atual. O outro era… órfão, de um login antigo, ainda rodando.
Passo 2: a origem do bash gordo
Um bash que consome memória sem você ter feito nada é sinal de que ele está rodando alguma coisa em loop. Pra descobrir o quê, vi a hora de início do processo:
ps -o pid,lstart,cmd -p <PID>
O processo era de dias atrás, ainda ativo. E o cmd apontava pra bash -l (login shell). Um login shell de dias atrás não deveria existir.
Aqui entrou o insight que mudou o diagnóstico: todo login shell carrega o ~/.bashrc. Se o .bashrc tem uma função que chama a si mesma (por erro de digitação num alias), cada login inicia um loop que cresce devagar. Fui olhar.
Passo 3: o .bashrc que corrompe sozinho
Abri o ~/.bashrc e procurei por funções. Encontrei uma que tinha sido adicionada na pressa, tipo:
empurrar() {
empurrar "$1"
}
Olhaí: empurrar chama empurrar. Recursão infinita sem caso base. Sempre que um login shell carregava o .bashrc e alguém chamava essa função (ou ela era chamada por outro alias), a memória começava a subir. Lento o suficiente pra VM aguentar horas antes de ficar inutilizável; constante o suficiente pra “aleatoriamente” derrubar tudo.
Corrigi eliminando a recursão (a função era pra empurrar chaves SSH, não pra chamar a si mesma). E, mais importante, garanti que nenhum login antigo ficasse rodando:
# Matou os shells órfãos
pkill -u $USER -o bash
Depois disso, a RAM da VM estabilizou num patamar normal. A lentidão “aleatória” sumiu.
Passo 4: separar CPU de rede
A CPU não era o problema. Mas a VM ainda parecia lenta no SSH. Aqui entra a distinção importante: lentidão percebida não é só CPU/RAM — também é latência de rede. Testei:
# Latência até o gateway Tailscale
ping -c 5 100.x.x.x
# Throughput pra um host conhecido
curl -o /dev/null -w "%{time_total}\n" https://cloudflare.com/cdn-cgi/trace
O ping estava normal. O curl estava rápido. Conclusão: a rede não era o problema. A lentidão no SSH vinha do shell ser lento pra responder — ou seja, do .bashrc (que o SSH carrega no login) estar fazendo trabalho desnecessário.
Encontrei também um neofetch (aquele print ASCII do sistema) sendo chamado em todo login. Em VM ARM com pouca CPU, o neofetch adiciona 1-2 segundos de atraso percebido em cada SSH. Pequeno, mas perceptível, e desnecessário.
A auditoria como procedimento fixo
Depois dessa sessão, fixei um procedimento de auditoria que rodo quando a VM fica lenta. Sempre na mesma ordem, sempre os mesmos comandos:
# 1. O que está consumindo agora (CPU e memória)
ps aux --sort=-%mem | head -10
ps aux --sort=-%cpu | head -10
# 2. Disco cheio? (causa misteriosa de lentidão)
df -h /
# 3. Tem processo órfão?
ps -o pid,lstart,cmd -u $USER | grep -v '?'
# 4. Rede
ping -c 3 <host-exemplo>
Quatro comandos, trinta segundos. Em 80% dos casos, um deles aponta a causa. O ponto não é decorar comandos — é ter um procedimento fixo pra não recomeçar do zero toda vez que algo fica lento.
O que aprendi
A lição que sobrevive fora deste caso: “está lento” é sintoma, nunca diagnóstico. Toda vez que achei que era a VM sendo fraca, eu estava palpitando — e o palpite me impedia de medir. A auditoria por evidência (CPU? RAM? disco? rede? processo órfão?) é mais lenta no primeiro minuto e muito mais rápida no total, porque te leva à causa em vez de te levar a reiniciar.
E o segundo aprendizado, mais específico: toda função que você escreve no .bashrc vira parte do boot do seu ambiente. Erro de digitação num script de uso eventual te dá erro visível; erro de digitação no .bashrc te dá lentidão invisível que ninguém conecta à causa. Trate o .bashrc como produção: teste antes de salvar, heredoc pra inserir blocos, e jamais recursão sem caso base.
Comentários
Carregando comentários…