Análise de Dumps de Memória na JVM

Analisar arquivos de despejo de heap da JVM (Heap Dump, geralmente no formato .hprof) é uma técnica fundamental para diagnosticar vazamentos de memória, crescimento anormal de objetos e problemas de GC. Abaixo está um guia completo para visualizar e analisar arquivos de despejo de heap, cobrindo seleção de ferramentas, etapas de operação e interpretação de indicadores-chave.

I. O que é um Despejo de Heap (Heap Dump)?

  • Definição: Um instantâneo de todos os objetos vivos na memória da JVM em um determinado momento.
  • Formato: Normalmente formato HPROF (arquivo .hprof).
  • Métodos de geração:
  • Manual: jmap -dump:format=b,file=heap.hprof <pid>
  • Automático: Parâmetro JVM -XX:+HeapDumpOnOutOfMemoryError
  • Ferramentas: jcmd <pid> GC.run_finalization (com parâmetros adicionais)

️ Importante: O despejo de heap contém apenas objetos Java no heap de memória, excluindo memória fora do heap como Metaspace e Direct Buffer.

II. Ferramentas Principais para Análise

Ferramenta Tipo Características Casos de Uso
Eclipse MAT (Memory Analyzer Tool) GUI Desktop Poderosa, detecção automática de vazamentos, suporte a OQL Recomendação principal
VisualVM GUI Desktop Incluída no JDK (versões antigas), leve Verificação rápida, análise básica
JProfiler GUI Comercial Monitoramento em tempo real + análise de heap, excelente experiência Análise profunda empresarial
YourKit GUI Comercial Similar ao JProfiler Análise de desempenho profissional
jhat (obsoleta) Linha de Comando + Web Incluída no JDK mas com baixo desempenho, removida do JDK 9+ Não recomendado
Scripts de linha de comando (como jcmd + OQL) CLI Análise automatizada CI/CD ou processamento em lote

Fortemente recomendado usar Eclipse MAT — gratuito, de código aberto, inteligente e com boa comunidaed.

III. Usando Eclipse MAT para Analisar Despejo de Heap (Passos Detalhados)

Passo 1: Baixar e Instalar o MAT

Passo 2: Abrir Arquivo .hprof

  • Iniciar MAT → FileOpen Heap Dump
  • Selecionar seu arquivo heap.hprof
  • Primeira carregamento gera índice (pode ser lento, dependendo do tamanho do heap)

Passo 3: Visualizações de Análise Chave

(1) Relatório de Suspeitos de Vazamento (Leak Suspects Report)

  • Após análise automática pelo MAT (ou clique em ReportsLeak Suspects)
  • Exibe pontos mais prováveis de vazamento de memória (como coleções grandes não liberadas, referências estáticas, etc.)
  • Inclui árvore dominadora (Dominator Tree) e cadeia de referências (Path to GC Roots)

Exemplo de saída:

Uma instância de "java.util.ArrayList" carregada por "sun.misc.Launcher$AppClassLoader @ 0x7a8b..." 
está consumindo 85% do heap (1.2 GB).
Caminho Mais Curto para Raízes GC: 
  class com.example.Cache → campo estático instances → ArrayList


(2) Histograma (Histogram)

  • Menu: WindowHistogram
  • Estatísticas por nome de classe de quantidade de objetos & heap superficial (Shallow Heap)
  • Clique com botão direito no nome da classe → Merge Shortest Paths to GC Rootsexcluir referências fracis/softs→ Verificar quem está referenciando fortemente ipmedindo a coleta

(3) Árvore Dominadora (Dominator Tree)

  • Menu: WindowDominator Tree
  • Ordenado por conjunto retido (Retained Heap) (ou seja, memória total liberada se o objeto for coletado)
  • Foco em objetos com Retained Heap grande

(4) OQL (Object Query Language)

  • Similar a SQL, para consultar objetos específicos
  • Exemplo: ``` SELECT * FROM java.util.HashMap WHERE size > 10000 SELECT toString(name) FROM com.example.Usuario

IV. Usando VisualVM para Análise (Incluída no JDK, adequada para verificação rápida)
--------------------------------

> Adequado para JDK 8 ~ JDK 10 (JDK 11+ requer download separado)

### Passos:

1. Iniciar `jvisualvm` (localizado em `$JAVA_HOME/bin/`)
2. `File` → `Load` → Selecionar arquivo `.hprof`
3. Verificar:
- **Summary**: Tamanho total do heap, algoritmo GC
- **Classes**: Estatísticas por classe de instâncias e uso
- **Instances**: Verificar conteúdo de objetos específicos (selecionar classe)
- **OQL Console**: Executar consultas de objetos

> ️ Desvantagem: Arquivos de heap grandes (>2GB) podem travar, com funcionalidades menos poderosas que MAT.

V. Interpretação de Indicadores-Chave de Análise
-----------

| Conceito | Descrição | Significado na Análise |
|---|---|---|
| **Shallow Heap** | Memória usada pelo próprio objeto (excluindo objetos referenciados) | Geralmente pequeno, exceto para arrays grandes |
| **Retained Heap** | Memória total liberada se o objeto for coletado (incluindo todos objetos referenciados) | **Indicador central para identificar vazamentos de memória** |
| **GC Roots** | Objetos que não são coletados pela JVM (variáveis de stack de thread, variáveis estáticas, referências JNI, etc.) | Objetos vazados geralmente são referenciados indiretamente por GC Roots |
| **Dominators** | Se A domina B, todos caminhos de GC Root para B passam por A | Árvore dominadora ajuda a localizar objeto raiz do problema |

VI. Cenários Típicos de Vazamento de Memória e Métodos de Análise
-----------------

### Cenário 1: Cache de coleção estático crescendo infinitamente

- **Sintoma**: `HashMap` / `ArrayList` com Retained Heap extremamente grande
- **Análise**:
1. Encontrar `java.util.HashMap` no Histograma
2. Clique com botão direito → `Merge Shortest Paths to GC Roots` → `excluir referências fracis/softs`
3. Descobrir caminho: `static Cache.map → HashMap`
- **Solução**: Implementar política de descarte LRU, definir maxSize

### Cenário 2: Listeners/callbacks não desregistrados

- **Sintoma**: Grande quantidade de objetos `Listener`, `Handler`
- **Análise**: Na Árvore Dominadora, esses objetos são referenciados fortemente por um gerenciador
- **Solução**: Prover método `unregister()` e chamá-lo no momento adequado

### Cenário 3: ThreadLocal não limpo

- **Sintoma**: `ThreadLocalMap` com alto consumo
- **Análise**: Cada thread tem `ThreadLocalMap` com grande quantidade de entries
- **Solução**: Chamar `ThreadLocal.remove()` após uso

VII. Análise Automatizada via Linha de Comando (Avançado)
---------------

### Usando `jcmd` + OQL (requer ferramentas complementares)

MAT suporta modo linha de comando (para CI):


Gerar relatório de vazamento (sem GUI)

mat -console -application org.eclipse.mat.api.parse
heap.hprof relatorio_vazamento.zip


### Usando `jhat` (apenas para pequenos arquivos, não recomendado)


jhat heap.hprof

Acessar http://localhost:7000


VIII. Precauções
--------

1. **Arquivos de despejo de heap são grandes** (geralmente próximo ao tamanho `-Xmx`), garantir espaço em disco suficiente.
2. **Geração de despejo de heap causa STW (Stop-The-World)**, usar com cuidado em produção.
3. **Risco de informações sensíveis**: O heap contém todos os dados dos objetos (senhas, informações de usuário), controlar permissões do arquivo.
4. **Gerar despejo de heap em contêineres**: ```
# Garantir que o diretório seja gravável
jmap -dump:format=b,file=/tmp/heap.hprof <pid>
kubectl cp <pod>:/tmp/heap.hprof ./heap.hprof


IX. Fluxo de Práticas Recomendadas

  1. Obter despejo de heap:
  • Automático em OOM: -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/
  • Disparo manual: jmap -dump:live,format=b,file=heap.hprof <pid>
  1. Baixar para local (ou máquina intermediária)
  2. Abrir com Eclipse MAT
  3. Verificar primeiro o Leak Suspects Report
  4. Combinar Histograma + Dominator Tree para localizar causa raiz
  5. Corrigir código + adicionar monitoramento (como Prometheus + JVM Exporter)

Conclusão

Ferramenta Recomendação Público-Alvo
Eclipse MAT ⭐⭐⭐⭐⭐ Todos desenvolvedores, SRE
VisualVM ⭐⭐⭐ Verificação rápida, arquivos de heap pequenos
JProfiler ⭐⭐⭐⭐ Usuários empresariais pagantes
Linha de comando ⭐⭐ Cenários automatizados

Lembre-se: "Retained Heap grande + não pode ser coletado pelo GC" = vazamento de memória**"Path to GC Roots" = caminho do vazamento**

Tags: JVM Eclipse MAT VisualVM memory analysis heap dump

Publicado em 6-19 05:06