Heap Dump: qué es, análisis del heap y eliminación de fugas de memoria

Autor: IT Sectr Publicado: 2026-05-07 Tiempo de lectura: 10 min

Heap Dump (volcado de heap) es una instantánea de la memoria dinámica de una aplicación que contiene información completa sobre todos los objetos vivos: sus clases, tamaños, referencias mutuas y accesibilidad desde las raíces GC. Heap Dump es la herramienta principal para analizar fugas de memoria y optimizar el consumo de recursos. Según Android Developers, el análisis de heap dumps permite detectar hasta el 95% de las fugas de memoria, incluyendo referencias cíclicas, listeners olvidados y referencias estáticas no liberadas.

Puntos Clave

  • Heap Dump es una instantánea de toda la memoria dinámica de la aplicación con información sobre cada objeto y las referencias entre ellos.
  • Android Studio Memory Profiler permite capturar heap dumps en tiempo real para aplicaciones Java y Kotlin.
  • Xcode Instruments proporciona la herramienta Allocations para crear y analizar heap dumps en iOS/macOS.
  • Shallow y retained size son métricas clave: shallow es el tamaño del objeto en sí, retained es el tamaño del objeto más todos los objetos que retiene.
  • El análisis de un heap dump incluye la búsqueda en el dominator tree, los objetos con mayor retained size y las rutas más cortas a las raíces GC.

Qué es un heap dump y para qué sirve

Heap dump es un volcado completo del heap de la máquina virtual — el área de memoria donde residen todos los objetos creados dinámicamente. En Java y Kotlin es el heap Dalvik/ART en Android, en Swift y Objective-C es el heap gestionado por ARC en iOS. Un heap dump captura cada objeto, su clase, tamaño, campos, referencias a otros objetos y banderas de accesibilidad desde las raíces GC (variables de pila, campos estáticos, referencias JNI).

El propósito principal de un heap dump es la detección de fugas de memoria. Una fuga ocurre cuando una aplicación sigue manteniendo referencias a objetos que ya no son necesarios, impidiendo su recolección por el garbage collector (o liberación mediante ARC). Causas típicas: listeners de eventos no desregistrados al destruir una activity; singletons con referencias al contexto; closures que capturan self; colecciones estáticas donde se añaden datos sin eliminarlos. Un heap dump ofrece una imagen precisa: qué objetos están “vivos”, cuáles son innecesarios y quién exactamente los referencia.

Según Google I/O, más del 60% de los informes de crash en aplicaciones Android están relacionados con OutOfMemoryError, y en el 80% de los casos la causa principal es una fuga de memoria detectable mediante heap dump. Para las aplicaciones iOS la situación es similar: las fugas debidas a retain cycles son una de las causas más comunes de caídas, identificadas mediante el instrumento Allocations en Xcode.

Cuándo se necesita un heap dump

Se debe realizar un heap dump cuando aparecen los siguientes síntomas: la aplicación consume memoria de forma lineal durante acciones repetitivas (navegar de un lado a otro entre pantallas); después de cerrar una pantalla, la memoria no vuelve al nivel inicial; aparecen OutOfMemoryError o advertencias de memoria en iOS; la aplicación termina por superar el límite de memoria (EXC_RESOURCE_RESOURCE en iOS). La recolección regular de heap dumps forma parte del protocolo de cultura de ingeniería en grandes proyectos móviles como Instagram y Spotify.

Heap dump en Android Studio: obtención y análisis

Android Studio proporciona Memory Profiler — una herramienta integrada para capturar heap dumps en tiempo real. Se accede a través de View → Tool Windows → Profiler. Tras iniciar la aplicación, seleccione la sesión, vaya a la pestaña Memory y haga clic en Dump Java Heap. Android Studio pausa la aplicación, realiza un volcado del heap ART y carga el resultado para su análisis. El archivo de volcado tiene formato .hprof — el estándar HPROF compatible con la mayoría de analizadores de memoria.

Después de cargar el volcado, Android Studio muestra una tabla de objetos con columnas: Allocations (cantidad de instancias), Native Size (memoria fuera del heap ART), Shallow Size (memoria del propio objeto), Retained Size (memoria del objeto incluyendo todo su subgrafo). El filtrado por nombre de clase, la ordenación por retained size y la búsqueda por paquetes permiten encontrar rápidamente las áreas problemáticas.

kotlin
// Fuga típica — un listener no desregistrado en 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()
        // ❌ Falta sensorManager.unregisterListener(listener)
        // → La Activity no será recolectada por GC, el heap dump mostrará la fuga
    }
}

Análisis del dominator tree en Android Studio

La pestaña Dominator Tree muestra los objetos que retienen la mayor cantidad de memoria. Si se elimina un objeto del dominator tree, toda la memoria que retiene queda disponible para la recolección. Esta es una herramienta clave: en lugar de revisar miles de objetos, te centras en 10–20 que controlan el 80–90% de la memoria. Según Google, el análisis del dominator tree es la forma más eficaz de encontrar un punto de fuga, reduciendo el tiempo de análisis de horas a minutos.

Heap dump en Xcode Instruments: Allocations y Leaks

Xcode Instruments proporciona dos herramientas para trabajar con heap dumps: Allocations — captura de volcados de heap con gráfico de consumo en tiempo real; Leaks — búsqueda automática de fugas mediante análisis de retain cycles. Allocations muestra todos los objetos en el heap, su tamaño, número de creaciones (allocations) y liberaciones (deallocations). La diferencia entre el número de creaciones y liberaciones para una clase concreta indica una posible fuga.

La captura de un heap dump en Allocations se realiza con el botón Snapshot Memory — la herramienta pausa la aplicación y toma un volcado completo. Después están disponibles las vistas estándar: lista de objetos por clase, árbol de llamadas (call tree) para cada objeto y un generador de informes. A diferencia de Android Studio, Xcode no utiliza .hprof, sino que almacena los datos en su propio formato .trace compatible con Instruments.

swift
// Fuga típica de iOS — retain cycle mediante un closure
class NetworkManager {
    var onComplete: ((Data) -> Void)?

    func startRequest() {
        // ❌ El closure captura self — retain cycle
        onComplete = { data in
            self.process(data)
        }
    }
    func process(_ data: Data) {}
}

El instrumento Leaks detecta automáticamente retain cycles y fugas mediante el análisis del grafo de referencias. Marca los objetos con fugas con un icono púrpura y muestra la ruta hacia la raíz (GC root). Para eliminar un retain cycle, basta con añadir [weak self] o [unowned self] en la captura del closure. La ejecución regular del instrumento Leaks es un paso obligatorio en el pipeline de CI en equipos que usan Swift para desarrollo iOS.

swift
// Solución — referencia débil a self
onComplete = { [weak self] data in
    guard let self else { return }
    self.process(data)
}

Shallow size, retained size y dominator tree

Para un análisis correcto de un heap dump es necesario comprender tres métricas clave. Shallow size es el volumen de memoria que ocupa directamente el objeto: sus campos, cabecera (header) y alineación. Para un objeto Java/Kotlin típico, el shallow size es de 16–40 bytes. Retained size es el shallow size del objeto más la suma del shallow size de todos los objetos que solo son accesibles a través de este objeto (es decir, se convertirían en basura si se eliminara). Precisamente el retained size muestra el impacto real del objeto en el consumo de memoria.

MétricaDescripciónEjemplo
Shallow sizeTamaño del propio objeto en bytesBitmap (100×100) = 40 016 B
Retained sizeShallow size + todo lo que retieneActivity con View Tree = 2–5 MB
Deep sizeRetained size + objetos anidados de otros grafosScrollView con adaptador = 10–50 MB

Dominator tree es una estructura donde cada objeto referencia a su “dominador” — el objeto que controla su accesibilidad. Si se elimina el dominador, todos los objetos de su subárbol se convierten en basura. El análisis del dominator tree es la forma más rápida de encontrar qué objeto retiene más memoria. Según Eclipse MAT (Memory Analyzer Tool), el 90% de las fugas se detectan revisando el top-20 del dominator tree en 5 minutos.

Análisis de fugas de memoria mediante heap dump

El proceso de análisis de una fuga mediante heap dump consta de varios pasos. Paso 1: realice la acción que debería liberar memoria (cierre la pantalla, finalice la operación). Paso 2: invoque al GC (System.gc() en Android, snapshot forzado en Xcode) y haga un heap dump. Paso 3: encuentre los objetos que deberían haber sido destruidos (por ejemplo, una instancia de Activity después de finish). Paso 4: para el objeto sospechoso, ejecute Path to GC Roots — la cadena de referencias que mantiene vivo el objeto. La última referencia de la cadena es la causa de la fuga.

Path to GC Roots

La función Path to GC Roots está disponible en Android Studio Profiler, Eclipse MAT y Xcode Instruments. Muestra la cadena más corta de referencias desde una raíz GC hasta el objeto problemático. Excluyendo las referencias débiles (weak) y blandas (soft), obtendrá solo las fuertes (strong) — aquellas que realmente impiden la recolección. Según Square Engineering, el 70% de las fugas en aplicaciones Android se deben a solo dos patrones: referencias estáticas a Activity o Context y listeners registrados pero no desregistrados.

kotlin
// Ejemplo de fuga mediante referencia estática
object AppCache {
    private val cache = mutableMapOf<String, Any>()

    fun storeActivityReference(activity: Activity) {
        cache["current_activity"] = activity // ❌ ¡Fuga!
    }
}

// Solución: referencia débil
object AppCacheFixed {
    private val cache = mutableMapOf<String, WeakReference<Any>>()
}

Comparación de dos heap dumps

La técnica de modo comparación es uno de los métodos más eficaces para encontrar fugas. Haga un heap dump antes y después de una acción repetitiva (por ejemplo, cinco navegaciones a una pantalla y vuelta). Compare el número de instancias de las clases clave: si el número de Activity ha aumentado aunque todas las actividades se hayan cerrado — es una fuga. Android Studio y Eclipse MAT admiten la comparación automática de volcados con resaltado de diferencias. Según Google, la comparación de volcados permite encontrar fugas invisibles en un análisis único gracias al efecto de acumulación.

Recomendaciones prácticas para reducir el consumo de memoria

Basándose en el análisis de heap dumps en proyectos reales, se han desarrollado prácticas probadas de optimización de memoria. Utilice WeakReference para cachés, callbacks y referencias al contexto en objetos de larga duración. Desregistre los listeners en onPause/onDestroy para Android y deinit para iOS. Evite colecciones estáticas grandes — si son necesarias, use LruCache con límite de tamaño. Optimice los Bitmaps: cargue imágenes con el inSampleSize correcto, use Glide o Picasso con caché de disco.

Perfilado de memoria durante el desarrollo

Incluya la captura regular de heap dumps en su pipeline de CI. Configure una tarea que ejecute pruebas de UI instrumentadas, realice los escenarios de usuario clave y compare el heap dump con la línea base. Si el retained size crece más del 5% respecto a la línea base, la compilación se marca como regresión. Este enfoque se practica en Airbnb, Uber y otras empresas con altos requisitos de calidad. Según Uber Engineering, la implementación del análisis automático de heap dumps en CI redujo los errores relacionados con memoria en un 70% en un trimestre.

groovy
// Ejemplo de tarea Gradle para heap dump automático en CI
task profileMemory(type: Exec) {
    commandLine 'adb', 'shell',
        'am start -n com.example/.MainActivity'
    // Esperando carga
    doLast {
        exec { commandLine 'adb', 'shell',
            'am broadcast -a com.example.DUMP_HEAP' }
    }
}

Preguntas Frecuentes

¿Cuál es la diferencia entre shallow size y retained size?

Shallow size es el tamaño del propio objeto (campos + cabecera). Retained size es el tamaño del objeto más todos los objetos que se convertirían en basura si se eliminara. El retained size es el principal indicador del impacto de un objeto en el consumo de memoria.

¿Cómo hacer un heap dump en un dispositivo Android físico?

A través del Android Studio Profiler, seleccione el dispositivo y proceso, haga clic en Dump Java Heap. Alternativamente, mediante línea de comandos: adb shell am dumpheap PID /sdcard/dump.hprof, luego adb pull.

¿Por qué un heap dump puede ser enorme (500 MB+)?

Un heap dump incluye todos los objetos vivos. Si la aplicación utiliza cachés, Bitmaps o procesa grandes cantidades de datos, el volcado puede alcanzar cientos de megabytes. Filtre por clases o use Eclipse MAT para cargar solo el índice.

¿Se puede analizar un heap dump sin Android Studio?

Sí, use Eclipse MAT (Memory Analyzer Tool) — una herramienta gratuita para analizar archivos .hprof. Admite dominator tree, path to GC roots, comparación de volcados y detección automática de fugas mediante Leak Suspects Report.

¿Un heap dump reduce el rendimiento de la aplicación?

El volcado en sí — sí, porque la recolección del volcado pausa todos los hilos (stop-the-world). Sin volcado — no. Realice volcados en entornos controlados (banco de pruebas, CI), no en producción.

Resumen

  • Heap Dump es una instantánea completa del heap de la aplicación con información sobre cada objeto y las relaciones entre ellos.
  • Android Studio Memory Profiler y Xcode Instruments Allocations son las herramientas principales de captura de volcados.
  • Shallow size es el tamaño del propio objeto; retained size es el tamaño del objeto con todo su subgrafo de dependencias.
  • Dominator tree muestra los objetos que controlan la mayor cantidad de memoria.
  • Path to GC Roots es la cadena de referencias fuertes que impide que un objeto sea recolectado.
  • La comparación de dos heap dumps (antes/después de una acción) es el método más fiable para detectar fugas.
  • La automatización de la captura y análisis de heap dumps en CI previene regresiones de memoria durante el desarrollo.

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también