DEV Community

Matheus de Camargo Marques
Matheus de Camargo Marques

Posted on

Guia de Sobrevivência JVM: Tuning de Performance para 16GB de RAM (Sem Swap)

Por Matheus de Camargo Marques

No desenvolvimento de software corporativo moderno, especialmente em ecossistemas robustos como o do Java Enterprise (WildFly, JBoss, Spring Boot), existe uma batalha constante entre a performance da IDE e a estabilidade do Servidor de Aplicação.

O cenário é clássico: você tem uma máquina de desenvolvimento "padrão de mercado" (16GB de RAM) e, por questões de performance de disco (SSD/NVMe) ou política da empresa, optou por trabalhar sem Swap (paginação em disco).

O desafio? Rodar o IntelliJ IDEA (que é faminto por memória), um WildFly (que carrega dezenas de módulos), Docker e Browser, sem que o Linux invoque o OOM Killer (Out of Memory Killer) e mate seu processo no meio de um debug.

Neste artigo, vamos analisar a anatomia do consumo de memória da JVM, a matemática real por trás dos travamentos e propor a configuração de "Ponto Doce" para este cenário.


1. A Matemática do Caos: O Erro da Soma Simples

Muitos desenvolvedores configuram a memória da JVM somando apenas o Heap (-Xmx).

"Vou dar 4GB para o servidor e 4GB para a IDE. Total 8GB. Tenho 16GB, então sobra 8GB. Tranquilo, certo?"

Errado.

A JVM consome memória muito além do Heap. Para entender o risco de rodar sem Swap, precisamos calcular o Footprint Total (Memória Comprometida):

A Conta Real (O Cenário Kamikaze)

Em um ambiente típico de desenvolvimento "Full Stack", veja para onde vão os seus 16GB quando você configura mal o Heap:

  1. WildFly (Configurado com 4GB Heap):

    • Heap: 4.0 GB
    • Metaspace (Classes carregadas): ~1.0 GB
    • Threads/Native/DirectBuffers: ~1.0 GB
    • Total Real: ~6.0 GB
  2. IntelliJ IDEA (Configurado com 3.5GB Heap):

    • Heap: 3.5 GB
    • Metaspace + GUI + Plugins: ~1.5 GB
    • CodeCache (JIT): ~0.5 GB
    • Total Real: ~5.5 GB
  3. Ambiente Auxiliar:

    • Docker (Postgres/Redis): ~1.0 GB
    • Google Chrome (Jira/Docs/StackOverflow): ~2.0 GB
    • Sistema Operacional (Kernel/Gnome/Shell): ~1.5 GB
    • Total Auxiliar: ~4.5 GB

Resultado: Você tem 0 bytes de margem.
Neste ponto, não existe memória livre para o File System Cache do Linux. O sistema começa a operar no limite crítico.


2. A Física do Travamento: Por que o PC congela?

Muitos acham que o PC trava porque a CPU está em 100%. Mas em ambientes Java sem Swap, o problema geralmente é o IO Wait e o CPU Scheduler.

Quando a RAM está totalmente cheia (100% de uso):

  1. Queda de Cache de Arquivos: O Linux é forçado a limpar todo o cache de disco da RAM para dar espaço à aplicação.
  2. Lentidão Extrema: Toda vez que você dá Alt+Tab ou o IntelliJ tenta ler um arquivo indexado, o sistema precisa ler fisicamente do SSD (que é milhares de vezes mais lento que a RAM), pois não há cópia em cache.
  3. Engarrafamento do Scheduler: As threads da CPU ficam em estado de espera (D-State ou Uninterruptible Sleep) aguardando o dado vir do disco. O Load Average dispara.
  4. OOM Killer: Se a aplicação pedir mais 1MB e não houver de onde tirar, o Kernel escolhe o processo mais gordo (WildFly ou IDEA) e o mata instantaneamente (SIGKILL).

3. O "Sweet Spot": A Configuração de Sobrevivência

Para manter a máquina ágil e impedir travamentos, precisamos aplicar o princípio da Segregação de Recursos. O objetivo é garantir que o SO tenha sempre 2GB a 3GB livres para cache de disco e respiro do sistema.

A. Tuning do IntelliJ IDEA

O IntelliJ é eficiente. Ele não precisa de 4GB para a maioria dos projetos. O segredo é garantir CodeCache (para a UI não travar) e reduzir o Heap.

Onde: Help -> Edit Custom VM Options
Ou editar dentro da pasta /bin do IntelliJ idea64.vmoptions jetbrains_client64.vmoptions

-Xms2048m
-Xmx2560m
-XX:ReservedCodeCacheSize=512m
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-Dsun.io.useCanonCaches=false

Enter fullscreen mode Exit fullscreen mode
  • Ganho: Reduzimos o teto de ~5.5GB para ~4.0GB (Total Real), economizando 1.5GB.

B. Tuning do WildFly (Standalone)

O servidor é o maior vilão de memória nativa. Além de reduzir o Heap, precisamos aplicar um hack específico do Linux.

Onde: bin/standalone.conf

# Heap: 3GB | Metaspace: 1GB (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

Enter fullscreen mode Exit fullscreen mode
  • Por que MALLOC_ARENA_MAX=2? A biblioteca padrão de alocação de memória do Linux (glibc) cria "arenas" de memória virtual para cada thread para evitar lock contention. Em servidores Java com muitas threads, isso causa uma fragmentação massiva, onde o processo consome muito mais RAM do que o Heap reporta. Limitar a 2 resolve esse vazamento fantasma.

4. A Verdade Nua e Crua: Isso é "Tampar o Sol com a Peneira"

Sejamos honestos: tudo o que discutimos acima — ajustar Heap, trocar Garbage Collector, contar megabytes — não é engenharia de software produtiva. É gestão de escassez.

Fazer tuning agressivo em uma máquina de 16GB para rodar um stack moderno (Backend + Frontend + Mobile + Docker) é, literalmente, tentar tampar o sol com a peneira.

O Custo Oculto

O tempo que você gasta investigando logs de GC, reiniciando a IDE ou fechando abas do navegador para liberar RAM, é tempo não codado. É prejuízo.

A Solução Definitiva: Hardware, não Software

A verdadeira solução não é uma flag mágica da JVM, mas sim prover o equipamento adequado.

Para o desenvolvedor que precisa rodar o ciclo completo (Backend + Frontend + Flutter), a configuração ideal de referência hoje é a arquitetura de Memória Unificada, como a encontrada nos MacBooks M4/M5 com 32GB (ou superior).

Por que essa arquitetura muda o jogo?

  1. Integração Total (SoC): CPU, GPU e RAM vivem no mesmo silício. Não há cópia de dados.
  2. Largura de Banda: A velocidade da memória é tão alta que o processador nunca fica esperando dados (o tal IO Wait desaparece).
  3. Swap Eficiente: Mesmo se você estourar os 32GB, o swap nesses sistemas é imperceptível para o uso desktop.

Conclusão:
Use este guia de tuning como um torniquete para estancar o sangramento imediato e conseguir trabalhar hoje. Mas entenda: desenvolvedores não devem perder tempo lutando contra configurações de VM. Se você está "de saco cheio" desses problemas, a culpa não é do Java. É da máquina que ficou pequena para o tamanho do seu talento.

Top comments (0)