Cómo inspeccionar el uso de memoria de tu app con el Generador de perfiles de memoria

El Generador de perfiles de memoria es un componente de Android Profiler que te ayuda a identificar fugas y pérdidas de memoria que puedan generar inestabilidades, fallas e incluso bloqueos de apps. Muestra un gráfico en tiempo real del uso de memoria de tu app y te permite capturar un volcado de montón, forzar la recolección de elementos no utilizados y realizar el seguimiento de asignaciones de memoria.

Para abrir Memory Profiler, sigue estos pasos:

  1. Haz clic en View > Tool Windows > Profiler (también puedes hacer clic en Profile , en la barra de herramientas).
  2. En la barra de herramientas de Android Profiler, selecciona el dispositivo y el proceso de la app del cual desees generar un perfil. Si conectaste un dispositivo mediante USB, pero no lo ves en la lista, asegúrate de haber habilitado la depuración por USB.
  3. Haz clic en cualquier parte del cronograma MEMORY para abrir Memory Profiler.

Como alternativa, puedes inspeccionar la memoria de tu app desde la línea de comandos con dumpsys y también ver eventos de recolección de elementos no utilizados en logcat.

Por qué debes generar perfiles para la memoria de tu app

Android proporciona un entorno de memoria administrada. Cuando determina que tu app ya no usa algunos objetos, el recolector de elementos no utilizados libera la memoria que no se usó para devolverla a la pila. La forma en la que Android busca memoria sin usar se somete a optimizaciones constantes. Sin embargo, en algún punto de todas las versiones de Android, el sistema debe pausar brevemente tu código. La mayoría de las veces, las pausas son imperceptibles. Sin embargo, si tu app asigna memoria a una velocidad que supera la que el sistema es capaz de alcanzar para recopilarla, tu app puede experimentar una demora mientras el recopilador libera suficiente memoria a fin de satisfacer tus asignaciones. La demora podría hacer que tu app omitiera marcos y causara una lentitud visible.

Aunque tu app no muestre lentitud, si tiene fugas de memoria, puede retener esa memoria incluso mientras se encuentre en segundo plano. Este comportamiento puede desacelerar el rendimiento del resto de la memoria del sistema forzando eventos innecesarios de recolección de elementos no utilizados. Finalmente, el sistema se ve forzado a finalizar el proceso de tu app para recuperar la memoria. Luego, cuando el usuario regresa a la app, esta debe reiniciarse por completo.

A fin de evitar estos problemas, debes usar el Generador de perfiles de memoria para lo siguiente:

  • Buscar en el cronograma patrones de asignación de memoria no deseados que puedan estar causando problemas de rendimiento
  • Volcar el montón de Java para ver qué objetos consumen memoria en un momento determinado (varios volcados de montón a lo largo de un período prolongado pueden ayudar a identificar fugas de memoria)
  • Registrar asignaciones de memoria durante interacciones normales e intensivas del usuario para determinar con exactitud si tu código asigna demasiados objetos en poco tiempo o si asigna objetos que se fugan

Para obtener más información sobre prácticas de programación que pueden reducir el uso de memoria de tu app, consulta Cómo administrar la memoria de tu app.

Descripción general del Generador de perfiles de memoria

Cuando abras el Generador de perfiles de memoria por primera vez, verás un cronograma detallado del uso de memoria de tu app y herramientas de acceso para forzar la recolección de elementos no utilizados, capturar un volcado de montón y registrar asignaciones de memoria.

Figura 1: Generador de perfiles de memoria

Como se indica en la figura 1, en la vista predeterminada del Generador de perfiles de memoria, se incluye lo siguiente:

  1. Un botón para forzar un evento de recolección de elementos no utilizados
  2. Un botón para capturar un volcado de montón.

    Nota: Solo aparecerá un botón para registrar las asignaciones de memoria a la derecha del botón de volcado del montón si estás conectado a un dispositivo con Android 7.1 (nivel de API 25) o una versión inferior.

  3. Un menú desplegable para especificar la frecuencia con la que el generador de perfiles captura las asignaciones de memoria (es posible que elegir la opción adecuada te ayude a mejorar el rendimiento de la app a la hora de generar el perfil)
  4. Botones para acercar y alejar la vista del cronograma
  5. Un botón para ir directo a los datos de memoria en tiempo real
  6. El cronograma de eventos, donde se muestran los estados de actividad, eventos de entrada del usuario y eventos de rotación de pantalla
  7. El cronograma de uso de memoria, que incluye lo siguiente:
    • Un gráfico de barras apiladas del volumen de memoria que se usa en cada categoría, como se indica con el eje Y a la izquierda, y la clave de color en la parte superior
    • Una línea punteada que indica la cantidad de objetos asignados, como se indica con el eje Y a la derecha
    • Un ícono para cada evento de recolección de elementos no utilizados

Sin embargo, si usas un dispositivo que ejecuta Android 7.1 o una versión anterior, no se verá toda la información de generación de perfiles de manera predeterminada. Si aparece el mensaje "Advanced profiling is unavailable for the selected process", deberás habilitar la generación de perfiles avanzada para ver lo siguiente:

  • El cronograma de eventos
  • La cantidad de objetos asignados
  • Los eventos de recolección de elementos no utilizados

En Android 8.0 y versiones posteriores, la generación de perfiles avanzada siempre se encuentra habilitada para apps depurables.

Cómo se registra la memoria

Los números que ves en la parte superior del Generador de perfiles de memoria (figura 2) se basan en todas las páginas privadas de memoria que confirma tu app, según el sistema Android. Este registro no incluye páginas compartidas con el sistema ni otras apps.

Figura 2: Leyenda del recuento de memoria en la parte superior del Generador de perfiles de memoria

Las categorías del recuento de memoria son las siguientes:

  • Java: Es la memoria de objetos asignados desde código Java o Kotlin.
  • Nativa: es la memoria de objetos asignados desde código C o C++.

    Incluso si no usas C++ en tu app, puedes ver memoria nativa usada aquí porque el framework de Android utiliza ese tipo de memoria para administrar varias tareas por ti; por ejemplo, cuando maneja elementos de imágenes y otros gráficos (aunque tu código esté en Java o Kotlin).

  • Gráficos: es la memoria usada para colas de búfer de gráficos con el propósito de mostrar píxeles en la pantalla, incluidas las superficies y texturas GL, entre otras opciones. Ten en cuenta que se trata de memoria compartida con la CPU, y no de memoria dedicada de la GPU.

  • Pila: es la memoria usada tanto por las pilas nativas como por las de Java en tu app. Esto normalmente se relaciona con la cantidad de subprocesos en ejecución que tiene tu app.

  • Código: es la memoria que tu app usa para código y recursos, como código de bytes dex, código dex optimizado o compilado, bibliotecas .so y fuentes.

  • Otras: esta categoría incluye la memoria usada por tu app que el sistema no sabe cómo categorizar.

  • Asignada: es la cantidad de objetos Java y Kotlin asignados por tu app. No se tienen en cuenta los objetos asignados en C o C++.

    Cuando se establece conexión con un dispositivo que ejecuta Android 7.1 o una versión anterior, este recuento de asignación comienza solamente en el momento en el que se conecta el Generador de perfiles de memoria a tu app en ejecución. Por lo tanto, no se tienen en cuenta los objetos asignados antes de que inicies la generación de perfiles. Sin embargo, en Android 8.0, se incluye una herramienta de generación de perfiles en el dispositivo que realiza un seguimiento de todas las asignaciones, por lo que este número siempre representa la cantidad total de objetos Java pendientes en tu app en Android 8.0 y versiones posteriores.

Cuando se compara con los recuentos de memoria de la herramienta anterior (Android Monitor), el nuevo Generador de perfiles de memoria registra tu memoria de manera diferente, por lo que podría parecer que el uso ahora es más elevado. El Generador de perfiles de memoria supervisa algunas categorías adicionales que aumentan el total; pero, si solo te importa la memoria del montón de Java, el número de "Java" debería ser similar al valor de la herramienta anterior. Además, aunque es probable que el número de Java no sea exactamente igual al que viste en Android Monitor, la cifra nueva contempla todas las páginas de memoria física asignadas al montón de Java de tu app desde que se bifurcó a partir de Zygote. Por lo tanto, se proporciona una representación precisa del volumen de memoria física que realmente usa tu app.

Cómo ver asignaciones de memoria

Las asignaciones de memoria te muestran cómo se asignó cada objeto Java y referencia de JNI en la memoria. Específicamente, el Generador de perfiles de memoria puede mostrarte lo siguiente sobre la asignación de objetos:

  • Qué tipos se asignaron y cuánto espacio ocupan
  • El seguimiento de pila de cada asignación, incluido el subproceso
  • El momento en que se desasignaron (solo cuando se usa un dispositivo con Android 8.0 o una versión posterior)

Si tu dispositivo ejecuta Android 8.0 o una versión posterior, puedes ver las asignaciones de tus objetos en cualquier momento arrastrando el cronograma a fin de seleccionar la región para la que deseas ver las asignaciones (como se muestra en el video 1). No hay necesidad de comenzar una sesión de registro, ya que Android 8.0 y las versiones posteriores incluyen una herramienta de generación de perfiles en el dispositivo que realiza un seguimiento de las asignaciones de tu app de forma constante.

Video 1: En el caso de Android 8.0 y versiones posteriores, selecciona un área del cronograma existente para ver las asignaciones de objetos

Si tu dispositivo ejecuta Android 7.1 o una versión anterior, haz clic en Record memory allocations , en la barra de herramientas del Generador de perfiles de memoria. Durante el registro, este rastrea todas las asignaciones que se producen en tu app. Cuando termines, haz clic en Stop recording (el mismo botón; mira el video 2) para ver las asignaciones.

Video 2: Con Android 7.1 y versiones anteriores, debes registrar las asignaciones de memoria de manera explícita.

Cuando selecciones una región del cronograma (o cuando termines una sesión de registro con un dispositivo que ejecute Android 7.1 o una versión anterior), aparecerá debajo la lista de objetos asignados, y se mostrarán los objetos agrupados por nombre de clase y ordenados por recuento de montón.

Para inspeccionar el registro de asignaciones, sigue estos pasos:

  1. Explora la lista para encontrar objetos que tengan recuentos de montón inusualmente elevados y que podrían experimentar fugas. Para que te resulte más sencillo encontrar clases conocidas, haz clic en el encabezado de la columna Class Name a fin de mostrarlas en orden alfabético. Luego, haz clic en el nombre de una clase. Aparecerá el panel Instance View a la derecha y, en él, se mostrará cada instancia de la clase, como puede verse en la figura 3.
    • De manera alternativa, puedes ubicar objetos rápidamente haciendo clic en Filter o presionando Ctrl + F (Cmd + F en Mac) e ingresando el nombre de una clase o paquete en el campo de búsqueda. También puedes buscar por nombre de método si seleccionas Arrange by callstack en el menú desplegable. Si deseas utilizar expresiones regulares, marca la casilla junto a Regex. También puedes marcar Match case si tu búsqueda distingue entre mayúsculas y minúsculas.
  2. En el panel Instance View, haz clic en una instancia. Aparecerá debajo la pestaña Call Stack y, en ella, se mostrará el punto en que se asignó esa instancia y el subproceso.
  3. En la pestaña Call Stack, haz clic con el botón derecho en cualquier línea y elige Jump to Source para abrir ese código en el editor.

Figura 3: Los detalles de cada objeto asignado aparecen en la opción Instance View, ubicada a la derecha

Puedes usar los dos menús que aparecen encima de la lista de objetos asignados para elegir qué montón inspeccionar y cómo organizar los datos.

En el menú de la izquierda, elige qué montón inspeccionar:

  • default heap: el sistema no especifica un montón.
  • image heap: es la imagen de inicio del sistema, que contiene clases precargadas durante ese período. Se garantiza que estas asignaciones nunca se moverán ni desaparecerán.
  • zygote heap: es el montón de copia en escritura en el que se bifurca un proceso de la app en el sistema Android.
  • app heap: es el montón principal en el que asigna memoria tu app.
  • JNI heap: es el montón que muestra dónde se asignan y liberan las referencias de la interfaz nativa de Java (JNI).

En el menú ubicado a la derecha, elige cómo organizar las asignaciones:

  • Arrange by class: agrupa todas las asignaciones según el nombre de la clase. Es el valor predeterminado.
  • Arrange by package: agrupa todas las asignaciones según el nombre del paquete.
  • Arrange by callstack: agrupa todas las asignaciones en su pila de llamadas correspondiente.

Cómo mejorar el rendimiento de la app durante la generación de perfiles

Para mejorar el rendimiento de tu app durante la generación de perfiles, la herramienta muestra, de forma predeterminada, las asignaciones de memoria periódicamente. Cuando realizas pruebas en dispositivos con nivel de API 26 o superior, puedes cambiar este comportamiento mediante el menú desplegable Allocation Tracking. Las opciones disponibles son las siguientes:

  • Full: captura todas las asignaciones de objetos en la memoria. Este es el comportamiento predeterminado en Android Studio 3.2 y versiones anteriores. Si tu app asigna una gran cantidad de objetos, es posible que se produzcan ralentizaciones visibles en ella durante la generación de perfiles.
  • Sampled: muestra las asignaciones de objetos en la memoria a intervalos regulares. Esta es la opción predeterminada y tiene menos impacto en el rendimiento de la app durante la generación de perfiles. Es posible que las apps que asignan una gran cantidad de objetos en un corto intervalo de tiempo muestren ralentizaciones visibles.
  • Off: detiene el seguimiento de la asignación de memoria de tu app.

Cómo ver referencias globales de JNI

La interfaz nativa de Java (JNI) es un framework que permite que se llamen entre sí el código Java y el código nativo.

Las referencias de JNI se administran manualmente mediante código nativo, por lo que es posible que los objetos Java que utilice el código nativo se mantengan activos durante demasiado tiempo. Algunos objetos del montón de Java pueden llegar a ser inalcanzables si se descarta una referencia de JNI sin primero borrarla de forma explícita. Además, es posible agotar el límite de referencias globales de JNI.

A fin de solucionar estos problemas, utiliza la vista JNI heap del Generador de perfiles de memoria para examinar todas las referencias globales de JNI y filtrarlas por tipos de Java y pilas de llamadas nativas. Con esta información, puedes encontrar cuándo y dónde se crean y se borran las referencias globales de JNI.

Mientras se esté ejecutando la app, selecciona una parte del cronograma que quieras inspeccionar y elige JNI heap en el menú desplegable de la parte superior de la lista, como se muestra más abajo. Podrás inspeccionar los objetos del montón como lo harías normalmente y hacer doble clic en los objetos de la pestaña Allocation Call Stack para ver dónde se asignan y se publican las referencias de JNI en tu código, tal como se muestra en la figura 4.

Figura 4: Visualización de referencias globales de JNI

A fin de inspeccionar las asignaciones de memoria para el código JNI de tu app, debes implementar tu aplicación en un dispositivo que ejecute Android 8.0 o una versión posterior.

Para obtener más información sobre JNI, consulta estas sugerencias relacionadas.

Generador de perfiles de memoria nativos

El Generador de perfiles de memoria de Android Studio ahora incluye la herramienta Generador de perfiles de memoria nativos para apps implementadas en dispositivos físicos que ejecutan Android 10 o versiones posteriores. La versión de vista previa de Android Studio 4.2 ofrece compatibilidad con dispositivos con Android 11.

El Generador de perfiles de memoria nativos realiza un seguimiento de las asignaciones o desasignaciones de objetos en código nativo para un período específico, y proporciona la siguiente información:

  • Allocations: es un recuento de objetos asignados a través de malloc() o el operador new durante el período seleccionado.
  • Deallocations: Es un recuento de objetos desasignados mediante free() o el operador delete durante el período seleccionado.
  • Allocations Size: Es el tamaño total en bytes de todas las asignaciones durante el período seleccionado.
  • Deallocations Size: Es el tamaño agregado en bytes de toda la memoria liberada durante el período seleccionado.
  • Total Count: Es el valor de la columna Allocations menos el valor de la columna Deallocations.
  • Remaining Size: Es el valor de la columna Allocations Size menos el valor de Deallocations Size.

Generador de perfiles de memoria nativos

Para iniciar una grabación, haz clic en Record native allocations, en la parte superior de la ventana del Generador de perfiles de memoria:

Botón Record native allocations

Cuando esté todo listo para completar la grabación, haz clic en Stop recording.

De forma predeterminada, el Generador de perfiles de memoria nativos usa un tamaño de muestra de 32 bytes: se toma una instantánea de la memoria cada vez que se asignan 32 bytes de memoria. Cuanto más pequeño sea el tamaño de muestra, más frecuentes serán las instantáneas, lo que generará datos más precisos sobre el uso de la memoria. Cuanto más grande sea el tamaño de muestra, menos precisos serán los datos generados, pero se consumirán menos recursos en el sistema y mejorará el rendimiento durante la grabación.

Para cambiar el tamaño de muestra del Generador de perfiles de memoria nativos, sigue estos pasos:

  1. Selecciona Run > Edit Configurations.
  2. Elige el módulo de tu app en el panel izquierdo.
  3. Haz clic en la pestaña Profiling y, luego, ingresa el tamaño de muestra en el campo Native memory sampling interval (bytes).
  4. Vuelve a compilar y ejecutar tu app.

Cómo capturar un volcado de montón

Un volcado de montón muestra los objetos de tu app que consumen memoria en el momento en que capturas el volcado. En particular, después de una sesión de usuario extensa, un volcado de montón puede ayudar a identificar fugas de memoria mostrando objetos que todavía están almacenados en ella y que, según tu criterio, ya no deberían estar ahí.

Cuando captures un volcado de montón, podrás ver lo siguiente:

  • Los tipos de objetos que asignó tu app y la cantidad de cada uno
  • El volumen de memoria que usa cada objeto
  • Los puntos en que existen referencias a cada objeto de tu código
  • La pila de llamadas del punto en que se asignó un objeto (actualmente, las pilas de llamadas están disponibles con un volcado de montón solo en el caso de Android 7.1 y versiones anteriores cuando capturas el volcado mientras registras las asignaciones)

Para capturar un volcado de montón, haz clic en Dump Java heap en la barra de herramientas del Generador de perfiles de memoria. Mientras se vuelca el montón, el volumen de memoria Java puede aumentar temporalmente. Esto es normal, ya que el volcado de montón ocurre en el mismo proceso que tu app y requiere memoria para recolectar datos.

El volcado de montón aparece debajo del cronograma de memoria, y se muestran todos los tipos de clases que contiene, como puede apreciarse en la figura 5.

Figura 4: Vista del volcado de montón

Si necesitas ser más preciso sobre el momento en que se debe crear el volcado, puedes crear un volcado de montón en el punto crítico del código de tu app llamando a dumpHprofData().

En la lista de clases, puedes ver la siguiente información:

  • Allocations: muestra la cantidad de asignaciones que contiene el montón.
  • Native Size: es la cantidad total (en bytes) de memoria nativa que utiliza este tipo de objeto. Esta columna solo se ve en Android 7.0 y versiones posteriores.

    Aquí, verás la memoria de algunos objetos asignados en Java debido a que Android usa memoria nativa para algunas clases de marcos de trabajo, como Bitmap.

  • Shallow Size: es la cantidad total (en bytes) de memoria Java que utiliza este tipo de objeto.

  • Retained Size: es el tamaño total (en bytes) de la memoria retenida debido a todas las instancias de esta clase.

Puedes usar los dos menús que aparecen encima de la lista de objetos asignados para elegir qué volcados de montón inspeccionar y cómo organizar los datos.

En el menú de la izquierda, elige qué montón inspeccionar:

  • default heap: el sistema no especifica un montón.
  • app heap: es el montón principal en el que asigna memoria tu app.
  • image heap: es la imagen de inicio del sistema, que contiene clases precargadas durante ese período. Se garantiza que estas asignaciones nunca se moverán ni desaparecerán.
  • zygote heap: es el montón de copia en escritura en el que se bifurca un proceso de la app en el sistema Android.

En el menú ubicado a la derecha, elige cómo organizar las asignaciones:

  • Arrange by class: agrupa todas las asignaciones según el nombre de la clase. Es el valor predeterminado.
  • Arrange by package: agrupa todas las asignaciones según el nombre del paquete.
  • Arrange by callstack: agrupa todas las asignaciones en su pila de llamadas correspondiente. Solo podrás usar esta función si capturas el volcado de montón mientras se registran las asignaciones. De todas formas, es posible que haya objetos en el montón que se asignen antes de que inicies el registro, por lo que esas asignaciones aparecerán primero, enumeradas por nombre de clase.

De forma predeterminada, la lista se ordena mediante la columna Retained Size. Si prefieres ordenarla por los valores de otra columna, haz clic en el encabezado correspondiente.

Haz clic en el nombre de una clase para abrir la ventana Instance View a la derecha (como se muestra en la figura 6). Cada instancia listada incluye lo siguiente:

  • Depth: es el menor número de saltos desde cualquier raíz de recolección de elementos no utilizados a la instancia seleccionada.
  • Native Size: Es el volumen de esta instancia en la memoria nativa. Esta columna solo se ve en Android 7.0 y versiones posteriores.
  • Shallow Size: Volumen de esta instancia en la memoria Java.
  • Retained Size: es el volumen de memoria que domina esta instancia (de acuerdo con el árbol de dominadores).

Figura 6: La duración necesaria para capturar un volcado de montón se indica en el cronograma

Para inspeccionar tu volcado, sigue estos pasos:

  1. Explora la lista para encontrar objetos que tengan recuentos de montón inusualmente elevados y que podrían experimentar fugas. Para que te resulte más sencillo encontrar clases conocidas, haz clic en el encabezado de la columna Class Name a fin de mostrarlas en orden alfabético. Luego, haz clic en el nombre de una clase. Aparecerá el panel Instance View a la derecha y, en él, se mostrará cada instancia de la clase, como puede verse en la figura 3.
    • De manera alternativa, puedes ubicar objetos rápidamente haciendo clic en Filter o presionando Ctrl + F (Cmd + F en Mac) e ingresando el nombre de una clase o paquete en el campo de búsqueda. También puedes buscar por nombre de método si seleccionas Arrange by callstack en el menú desplegable. Si deseas utilizar expresiones regulares, marca la casilla junto a Regex. También puedes marcar Match case si tu búsqueda distingue entre mayúsculas y minúsculas.
  2. En el panel Instance View, haz clic en una instancia. Aparecerá debajo la pestaña References y, en ella, se mostrarán todas las referencias al objeto en cuestión.

    También puedes hacer clic en la flecha junto al nombre de la instancia para ver todos sus campos y, luego, en el nombre de un campo para ver todas sus referencias. Asimismo, si deseas ver información de la instancia correspondiente a un campo, haz clic con el botón secundario en él y selecciona Go to Instance.

  3. En la pestaña References, si identificas una referencia que podría tener una fuga de memoria, haz clic con el botón secundario en ella y selecciona Go to Instance. De esta manera, se selecciona la instancia correspondiente del volcado de montón y se muestran sus propios datos de instancia.

En el volcado de montón, busca fugas de memoria ocasionadas por alguno de los siguientes elementos:

  • Referencias duraderas a Activity, Context, View, Drawable y otros objetos que pueden hacer referencia al contenedor Activity o Context
  • Clases internas no estáticas, como Runnable, que pueden contener una instancia Activity
  • Cachés que almacenan objetos más tiempo del necesario

Cómo guardar un volcado de montón como un archivo HPROF

Cuando capturas un volcado de montón, los datos pueden verse en el Generador de perfiles de memoria únicamente mientras este se encuentra en ejecución. Cuando sales de la sesión de generación de perfiles, se pierde el volcado. Por lo tanto, si quieres guardarlo para revisarlo más tarde, expórtalo como un archivo HPROF. En Android Studio 3.1 y versiones anteriores, el botón Export capture to file se encuentra en el lado izquierdo de la barra de herramientas, debajo del cronograma. En Android Studio 3.2 y versiones posteriores, se incluye un botón Export Heap Dump a la derecha de cada entrada de Heap Dump, en el panel Sessions. En el cuadro de diálogo Export As, guarda el archivo con la extensión de nombre de archivo .hprof.

Para usar un analizador de HPROF como jhat, debes convertir el archivo HPROF del formato de Android al formato SE HPROF de Java. Puedes hacerlo con la herramienta hprof-conv provista en el directorio android_sdk/platform-tools/. Ejecuta el comando hprof-conv con dos argumentos: el archivo HPROF original y la ubicación para escribir la versión convertida. Por ejemplo:

hprof-conv heap-original.hprof heap-converted.hprof

Cómo importar un archivo de volcado de montón

Para importar un archivo HPROF (.hprof), haz clic en Start a new profiling session en el panel Sessions, selecciona Load from file y elige el archivo desde el navegador.

También puedes importar un archivo HPROF arrastrándolo desde el explorador hasta una ventana del editor.

Detección de pérdidas en Memory Profiler

Cuando se analiza un volcado de montón en el Generador de perfiles de memoria, puedes filtrar los datos de perfiles que Android Studio cree que pueden indicar fugas de memoria para instancias Activity y Fragment en tu app.

Los tipos de datos que muestra el filtro incluyen los siguientes:

  • Instancias Activity que se destruyeron, pero a las que todavía se hace referencia.
  • Instancias Fragment que no tienen un FragmentManager válido, pero a las que aún se hace referencia

En ciertas situaciones, como las que se incluyen a continuación, el filtro puede generar falsos positivos:

  • Se creó un Fragment, pero todavía no se usó.
  • Se almacena en caché un Fragment, pero no como parte de un FragmentTransaction.

Para usar esta función, primero debes capturar un volcado de montón o importar un archivo de volcado de montón en Android Studio. Para mostrar los fragmentos y las actividades que pueden tener fugas de memoria, selecciona la casilla de verificación Activity/Fragment Leaks en el panel de volcado de montón del Generador de perfiles de memoria, como se muestra en la figura 7.

Generador de perfiles: detección de pérdidas de memoria

Figura 7: Filtrado de un volcado de montón para las pérdidas de memoria

Cómo generar perfiles de tu memoria

Al usar el Generador de perfiles de memoria, debes forzar el código de tu app e intentar que se produzcan fugas de memoria. Para ello, puedes permitir que se ejecute tu app durante un rato antes de inspeccionar el montón. Es posible que las fugas se desplacen hasta la parte superior de las asignaciones en el montón. Sin embargo, cuanto más pequeña sea la fuga, durante más tiempo deberás ejecutar la app para poder verla.

También puedes activar una fuga de memoria de una de las siguientes maneras:

  • Gira el dispositivo de la posición vertical a la horizontal y repite ese movimiento varias veces en diferentes estados de actividad. A menudo, la rotación del dispositivo puede hacer que en una app se produzca la fuga de un objeto Activity, Context o View debido a que el sistema recrea la Activity, y si tu app conserva una referencia a uno de esos objetos en otro lugar, el sistema no puede incluirlo en la recolección de elementos no utilizados.
  • Alterna tu app y otra en diferentes estados de actividad (navega hasta la pantalla principal y, luego, regresa a tu app).

Sugerencia: También puedes realizar los pasos anteriores usando el framework de prueba monkeyrunner.