Guia de Sobrevivência JVM: Tuning de Performance para 16GB de RAM (Sem Swap)
Source: Dev.to
Introdução
No desenvolvimento de software corporativo moderno, especialmente em ecossistemas robustos como Java Enterprise (WildFly, JBoss, Spring Boot), há uma batalha constante entre a performance da IDE e a estabilidade do servidor de aplicação.
O cenário típico: uma máquina de desenvolvimento padrão (16 GB de RAM) operando sem swap (por política da empresa ou por questões de desempenho de disco). O desafio é rodar IntelliJ IDEA, WildFly, Docker e um navegador sem que o Linux invoque o OOM Killer.
Consumo de memória da JVM
Muitos desenvolvedores configuram a memória da JVM somando apenas o heap (-Xmx). Essa prática ignora o consumo adicional da JVM, que inclui metaspace, threads, buffers nativos, entre outros.
Exemplo de alocação em um ambiente “Full Stack”
| Componente | Configuração | Heap | Metaspace / Outros | Total aproximado |
|---|---|---|---|---|
| WildFly | 4 GB Heap | 4 GB | Metaspace ~1 GB, Threads/Native/DirectBuffers ~1 GB | ~6 GB |
| IntelliJ IDEA | 3.5 GB Heap | 3.5 GB | Metaspace + GUI + Plugins ~1.5 GB, CodeCache ~0.5 GB | ~5.5 GB |
| Ambiente auxiliar | Docker (Postgres/Redis), Chrome, SO | – | Docker ~1 GB, Chrome ~2 GB, Sistema Operacional ~1.5 GB | ~4.5 GB |
Resultado: praticamente 0 GB de margem livre. Quando a RAM está 100 % ocupada, o Linux precisa limpar o cache de arquivos, provocando lentidão extrema e, eventualmente, o OOM Killer pode encerrar processos críticos (WildFly ou IDEA).
Estratégia de segregação de recursos
Para manter a máquina ágil, é recomendável reservar de 2 GB a 3 GB de RAM livre para o cache de disco e para o próprio sistema operacional.
Ajuste da IDE (IntelliJ IDEA)
Local: Help → Edit Custom VM Options
-Xms2048m
-Xmx2560m
-XX:ReservedCodeCacheSize=512m
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-Dsun.io.useCanonCaches=false
Ganho: redução do consumo total da IDE de ~5.5 GB para ~4.0 GB (economia de ~1.5 GB).
Ajuste do servidor de aplicação (WildFly)
Local: bin/standalone.conf
# Heap: 3 GB | Metaspace: 1 GB (máximo)
JAVA_OPTS="$JAVA_OPTS -Xms3072m -Xmx3072m -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=1024m"
JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
# O segredo do Linux (evita vazamento de memória nativa do glibc)
MALLOC_ARENA_MAX=2
export MALLOC_ARENA_MAX
Por que MALLOC_ARENA_MAX=2?
A biblioteca de alocação de memória do Linux (glibc) cria “arenas” de memória virtual para cada thread, o que pode gerar fragmentação massiva em servidores Java com muitas threads. Limitar o número de arenas a 2 reduz esse consumo “fantasma”.
Impacto do esgotamento de memória
Quando a RAM está totalmente ocupada:
- Cache de arquivos – O Linux limpa o cache para liberar espaço, aumentando o I/O.
- Lentidão extrema – Operações de leitura de arquivos passam a depender do SSD, muito mais lento que a RAM.
- Engarrafamento do scheduler – Threads ficam em estado de espera (D‑State), elevando o load average.
- OOM Killer – O kernel encerra o processo que mais consome memória.
Considerações finais
O tuning agressivo de JVM e de recursos do sistema pode mitigar problemas imediatos, mas não substitui hardware adequado. Para desenvolvedores que precisam rodar todo o stack (backend, frontend, mobile, Docker) em uma única máquina, a solução de longo prazo é investir em equipamentos com mais memória ou em arquiteturas de memória unificada (ex.: MacBooks com 32 GB ou mais).
Conclusão
- Use as configurações acima como um “torniquete” para estancar o sangramento imediato de memória.
- Reserve memória livre para o sistema operacional.
- Limite
MALLOC_ARENA_MAXpara evitar vazamento de memória nativa. - Avalie a necessidade de upgrade de hardware para evitar que desenvolvedores percam tempo lutando contra limitações de VM.