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
- Site oficial: https://www.eclipse.org/mat/
- Suporta Windows / macOS / Linux
- Descompactar e usar (baseado em Eclipse RCP)
Passo 2: Abrir Arquivo .hprof
- Iniciar MAT →
File→Open 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
Reports→Leak 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:
Window→Histogram - 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 Roots→excluir referências fracis/softs→ Verificar quem está referenciando fortemente ipmedindo a coleta
(3) Árvore Dominadora (Dominator Tree)
- Menu:
Window→Dominator 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
- Obter despejo de heap:
- Automático em OOM:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/ - Disparo manual:
jmap -dump:live,format=b,file=heap.hprof <pid>
- Baixar para local (ou máquina intermediária)
- Abrir com Eclipse MAT
- Verificar primeiro o Leak Suspects Report
- Combinar Histograma + Dominator Tree para localizar causa raiz
- 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**