Heap Dump (dump do heap) é uma captura da memória dinâmica do aplicativo contendo informações completas sobre todos os objetos vivos: suas classes, tamanhos, referências mútuas e acessibilidade a partir das raízes GC. Heap Dump é a principal ferramenta para analisar vazamentos de memória e otimizar o consumo de recursos. De acordo com Android Developers, a análise de heap dumps permite detectar até 95% dos vazamentos de memória, incluindo referências cíclicas, listeners esquecidos e referências estáticas não liberadas.
Pontos Principais
Heap dump é um despejo completo do heap da máquina virtual — a área de memória onde residem todos os objetos criados dinamicamente. Em Java e Kotlin é o heap Dalvik/ART no Android, em Swift e Objective-C é o heap gerenciado por ARC no iOS. Um heap dump captura cada objeto, sua classe, tamanho, campos, referências a outros objetos e flags de acessibilidade a partir das raízes GC (variáveis de pilha, campos estáticos, referências JNI).
O principal objetivo de um heap dump é a detecção de vazamentos de memória. Um vazamento ocorre quando um aplicativo continua mantendo referências a objetos que não são mais necessários, impedindo sua coleta pelo garbage collector (ou liberação via ARC). Causas típicas: listeners de eventos não cancelados ao destruir uma activity; singletons com referências ao contexto; closures que capturam self; coleções estáticas onde dados são adicionados sem remoção. Um heap dump fornece uma imagem precisa: quais objetos estão “vivos”, quais são desnecessários e quem exatamente está referenciando-os.
De acordo com Google I/O, mais de 60% dos relatórios de crash de aplicativos Android estão relacionados a OutOfMemoryError, e em 80% dos casos a causa raiz é um vazamento de memória detectável via heap dump. Para aplicativos iOS a situação é similar: vazamentos devido a retain cycles são uma das causas mais comuns de crashes, identificados através do instrumento Allocations no Xcode.
Um heap dump deve ser realizado quando os seguintes sintomas aparecem: o aplicativo consome memória linearmente durante ações repetitivas (navegar para frente e para trás entre telas); após fechar uma tela, a memória não retorna ao nível inicial; ocorrem OutOfMemoryError ou avisos de memória no iOS; o aplicativo termina por exceder o limite de memória (EXC_RESOURCE_RESOURCE no iOS). A coleta regular de heap dumps faz parte do protocolo de cultura de engenharia em grandes projetos móveis como Instagram e Spotify.
Android Studio fornece o Memory Profiler — uma ferramenta integrada para capturar heap dumps em tempo real. Acessível através de View → Tool Windows → Profiler. Após iniciar o aplicativo, selecione a sessão, vá para a aba Memory e clique em Dump Java Heap. O Android Studio pausa o aplicativo, realiza um dump do heap ART e carrega o resultado para análise. O arquivo de dump está no formato .hprof — o padrão HPROF compatível com a maioria dos analisadores de memória.
Após carregar o dump, o Android Studio exibe uma tabela de objetos com colunas: Allocations (quantidade de instâncias), Native Size (memória fora do heap ART), Shallow Size (memória do próprio objeto), Retained Size (memória do objeto incluindo todo seu subgrafo). A filtragem por nome de classe, ordenação por retained size e pesquisa por pacotes permitem encontrar rapidamente as áreas problemáticas.
// Vazamento típico — um listener não cancelado no onDestroy
class MainActivity : AppCompatActivity() {
private val sensorManager by lazy {
getSystemService(SENSOR_SERVICE) as SensorManager
}
private val listener = MySensorListener()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sensorManager.registerListener(listener,
sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
SensorManager.SENSOR_DELAY_NORMAL)
}
override fun onDestroy() {
super.onDestroy()
// ❌ Faltando sensorManager.unregisterListener(listener)
// → Activity não será coletada pelo GC, heap dump mostrará o vazamento
}
}
A aba Dominator Tree mostra os objetos que retêm a maior quantidade de memória. Se um objeto for removido do dominator tree, toda a memória que ele retém fica disponível para coleta. Esta é uma ferramenta-chave: em vez de examinar milhares de objetos, você foca em 10–20 que controlam 80–90% da memória. De acordo com Google, a análise do dominator tree é a forma mais eficaz de encontrar um ponto de vazamento, reduzindo o tempo de análise de horas para minutos.
Xcode Instruments fornece duas ferramentas para trabalhar com heap dumps: Allocations — captura de dumps de heap com gráfico de consumo em tempo real; Leaks — busca automática de vazamentos através da análise de retain cycles. Allocations exibe todos os objetos no heap, seu tamanho, número de criações (allocations) e liberações (deallocations). A diferença entre o número de criações e liberações para uma classe específica indica um potencial vazamento.
A captura de um heap dump no Allocations é feita com o botão Snapshot Memory — a ferramenta pausa o aplicativo e faz um dump completo. Depois disso, as visualizações padrão estão disponíveis: lista de objetos por classe, árvore de chamadas (call tree) para cada objeto e um gerador de relatórios. Ao contrário do Android Studio, o Xcode não usa .hprof, mas armazena dados em seu próprio formato .trace compatível com Instruments.
// Vazamento típico de iOS — retain cycle através de um closure
class NetworkManager {
var onComplete: ((Data) -> Void)?
func startRequest() {
// ❌ Closure captura self — retain cycle
onComplete = { data in
self.process(data)
}
}
func process(_ data: Data) {}
}
O instrumento Leaks detecta automaticamente retain cycles e vazamentos através da análise do grafo de referências. Ele marca objetos com vazamento com um ícone roxo e mostra o caminho para a raiz (GC root). Para eliminar um retain cycle, basta adicionar [weak self] ou [unowned self] na captura do closure. A execução regular do instrumento Leaks é uma etapa obrigatória no pipeline de CI em equipes que usam Swift para desenvolvimento iOS.
// Correção — referência fraca para self
onComplete = { [weak self] data in
guard let self else { return }
self.process(data)
}
Para uma análise correta de um heap dump é necessário compreender três métricas-chave. Shallow size é o volume de memória ocupado diretamente pelo objeto: seus campos, cabeçalho (header) e alinhamento. Para um objeto Java/Kotlin típico, o shallow size é de 16–40 bytes. Retained size é o shallow size do objeto mais a soma do shallow size de todos os objetos que são acessíveis apenas através deste objeto (ou seja, se tornariam lixo se ele fosse removido). O retained size mostra o impacto real do objeto no consumo de memória.
| Métrica | Descrição | Exemplo |
|---|---|---|
| Shallow size | Tamanho do próprio objeto em bytes | Bitmap (100×100) = 40.016 B |
| Retained size | Shallow size + tudo que ele retém | Activity com View Tree = 2–5 MB |
| Deep size | Retained size + objetos aninhados de outros grafos | ScrollView com adaptador = 10–50 MB |
Dominator tree é uma estrutura onde cada objeto referencia seu “dominador” — o objeto que controla sua acessibilidade. Se o dominador for removido, todos os objetos de sua subárvore se tornam lixo. A análise do dominator tree é a forma mais rápida de descobrir qual objeto retém mais memória. De acordo com Eclipse MAT (Memory Analyzer Tool), 90% dos vazamentos são detectados revisando o top-20 do dominator tree em 5 minutos.
O processo de análise de um vazamento via heap dump consiste em várias etapas. Etapa 1: realize a ação que deve liberar memória (feche a tela, finalize a operação). Etapa 2: chame o GC (System.gc() no Android, snapshot forçado no Xcode) e faça um heap dump. Etapa 3: encontre os objetos que deveriam ter sido destruídos (por exemplo, uma instância de Activity após finish). Etapa 4: para o objeto suspeito, execute Path to GC Roots — a cadeia de referências que mantém o objeto vivo. A última referência na cadeia é a causa do vazamento.
A função Path to GC Roots está disponível no Android Studio Profiler, Eclipse MAT e Xcode Instruments. Ela mostra a cadeia mais curta de referências de uma raiz GC até o objeto problemático. Excluindo referências fracas (weak) e suaves (soft), você obtém apenas as fortes (strong) — aquelas que realmente impedem a coleta. De acordo com Square Engineering, 70% dos vazamentos em aplicativos Android são causados por apenas dois padrões: referências estáticas para Activity ou Context e listeners registrados mas não cancelados.
// Exemplo de vazamento através de referência estática
object AppCache {
private val cache = mutableMapOf<String, Any>()
fun storeActivityReference(activity: Activity) {
cache["current_activity"] = activity // ❌ Vazamento!
}
}
// Correção: referência fraca
object AppCacheFixed {
private val cache = mutableMapOf<String, WeakReference<Any>>()
}
A técnica de modo de comparação é um dos métodos mais eficazes para encontrar vazamentos. Faça um heap dump antes e depois de uma ação repetitiva (por exemplo, cinco navegações para uma tela e volta). Compare o número de instâncias das classes-chave: se o número de Activity aumentou embora todas as atividades tenham sido fechadas — é um vazamento. Android Studio e Eclipse MAT suportam comparação automática de dumps com destaque de diferenças. De acordo com Google, a comparação de dumps permite encontrar vazamentos invisíveis em uma análise única devido ao efeito de acúmulo.
Com base na análise de heap dumps em projetos reais, práticas comprovadas de otimização de memória foram desenvolvidas. Use WeakReference para caches, callbacks e referências ao contexto em objetos de longa duração. Cancele os listeners em onPause/onDestroy para Android e deinit para iOS. Evite grandes coleções estáticas — se necessárias, use LruCache com limite de tamanho. Otimize os Bitmaps: carregue imagens com o inSampleSize correto, use Glide ou Picasso com cache de disco.
Inclua a captura regular de heap dumps em seu pipeline de CI. Configure uma tarefa que execute testes de UI instrumentados, realize os cenários de usuário principais e compare o heap dump com a linha de base. Se o retained size crescer mais de 5% em relação à linha de base, o build é marcado como regressão. Esta abordagem é praticada no Airbnb, Uber e outras empresas com altos requisitos de qualidade. De acordo com Uber Engineering, a implementação da análise automática de heap dumps no CI reduziu os erros relacionados à memória em 70% em um trimestre.
// Exemplo de tarefa Gradle para heap dump automático no CI
task profileMemory(type: Exec) {
commandLine 'adb', 'shell',
'am start -n com.example/.MainActivity'
// Aguardando carregamento
doLast {
exec { commandLine 'adb', 'shell',
'am broadcast -a com.example.DUMP_HEAP' }
}
}
Perguntas Frequentes
Shallow size é o tamanho do próprio objeto (campos + cabeçalho). Retained size é o tamanho do objeto mais todos os objetos que se tornariam lixo se ele fosse removido. O retained size é o principal indicador do impacto de um objeto no consumo de memória.
Através do Android Studio Profiler, selecione o dispositivo e processo, clique em Dump Java Heap. Alternativamente, via linha de comando: adb shell am dumpheap PID /sdcard/dump.hprof, depois adb pull.
Um heap dump inclui todos os objetos vivos. Se o aplicativo usa caches, Bitmaps ou processa grandes dados, o dump pode atingir centenas de megabytes. Filtre por classes ou use Eclipse MAT para carregar apenas o índice.
Sim, use Eclipse MAT (Memory Analyzer Tool) — uma ferramenta gratuita para analisar arquivos .hprof. Suporta dominator tree, path to GC roots, comparação de dumps e detecção automática de vazamentos via Leak Suspects Report.
O dump em si — sim, porque a coleta do dump pausa todas as threads (stop-the-world). Sem dump — não. Faça dumps em ambientes controlados (bancada de teste, CI), não em produção.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também