Uso de memoria del mapa de bits

Los mapas de bits suelen ser los objetos que más memoria consumen en una app. Las operaciones de decodificación y escalamiento suelen estar en la ruta crítica para la renderización de fotogramas. Si optimizas el uso de memoria de los mapas de bits, se obtienen mejoras significativas en la capacidad de respuesta de la IU, la duración de la batería y la estabilidad general, ya que se reducen los bloqueos, los ANR y las finalizaciones de procesos relacionados con OOM.

Identifica el uso elevado de memoria de mapas de bits

Android vitals proporciona métricas sobre el espacio en memoria de mapas de bits de una app mediante la agregación de datos de dispositivos Android. De forma predeterminada, estas métricas se calculan como un resumen de 28 días de datos diarios. Estos datos ayudan a identificar tendencias y posibles regresiones en la eficiencia de la memoria en diferentes tipos y versiones de dispositivos.

Android vitals comparte el uso de memoria de mapas de bits de tu app desglosado por los siguientes estados de proceso:

  • Primer plano: El proceso de la app es visible. Se espera que el P99 sea significativamente más alto en primer plano que en otros estados de proceso, pero los desarrolladores deben investigar si la relación P99/P50 es significativa (p.ej., superior a 3.5 veces), ya que esto suele indicar una fuga de memoria de mapas de bits. Para identificar esto, busca una divergencia entre el uso típico (P50) y el uso atípico (P99). Si bien la expansión general de recursos aumenta la memoria de manera uniforme en todos los percentiles, las fugas de memoria se acumulan con el tiempo, lo que sesga en gran medida los datos del extremo final (P99). Asegúrate de que las asignaciones de mapas de bits en primer plano no persistan de forma innecesaria después de que la app pase a otros estados.
  • Servicios percibidos por el usuario: El proceso de la app se ejecuta en un estado perceptible. Esto incluye servicios en primer plano, tareas aceleradas y tareas de transferencia de datos iniciadas por el usuario. Las apps no deben conservar asignaciones de mapas de bits pesadas en primer plano cuando pasan a estos estados. Debido a que estos servicios están diseñados para tareas de larga duración, conservar recursos grandes degrada la experiencia general del usuario y obliga al daemon Low Memory Killer (LMKD) a recuperar memoria mediante la finalización de procesos de menor prioridad.
  • Segundo plano: La app ejecuta un servicio en segundo plano o se ejecutó recientemente en segundo plano, pero aún no está almacenada en caché. Debido a que este estado de proceso es menos importante que los procesos en primer plano o perceptibles, las apps deben liberar explícitamente recursos de mapas de bits grandes aquí para reducir la presión de la memoria.
  • Almacenado en caché: La app está en un estado almacenado en caché. Este estado es muy sensible a la presión de la memoria del sistema, como los LMK. Las apps deben reducir de forma proactiva el uso de memoria de mapas de bits en este estado para evitar la expulsión por parte del SO.

Factores que contribuyen al uso elevado de memoria de mapas de bits

Es posible que también se incluya en el cálculo la memoria virtual que nunca se usó. Si ves un uso de memoria de mapas de bits inesperadamente alto, verifica que no estés asignando memoria que no se use.

Recursos

Analiza mapas de bits en Android Studio

Generación de perfiles de Android Studio para mapas de bits

Usa el Generador de perfiles de memoria para inspeccionar las asignaciones de memoria en tiempo real, capturar volcados de montón y analizar objetos en busca de fugas de memoria. Además, usa el analizador de montón para detectar fugas de memoria, identificar asignaciones de mapas de bits duplicadas y visualizar la retención de objetos.

Detección automática de fugas con LeakCanary

Integra la biblioteca de LeakCanary para automatizar la detección de fugas de memoria en tu app. LeakCanary proporciona un análisis automático del montón, identifica objetos que deberían haberse recolectado como elementos no utilizados, pero que aún se conservan en la memoria, como los mapas de bits retenidos por los componentes destruidos.

Documentación sobre el rendimiento de mapas de bits

Estos recursos proporcionan orientación integral sobre las prácticas recomendadas para el control eficiente de mapas de bits en diferentes componentes de Android.

Lista de tareas para desarrolladores para optimizar el uso de memoria de mapas de bits

Para optimizar la eficiencia de la memoria de mapas de bits, sigue los tres principios básicos: reducir, reutilizar y reciclar.

  • Reducir: Minimiza el espacio en memoria inicial cuando cargas o muestras mapas de bits.
  • Reutilizar: Implementa mecanismos de almacenamiento en caché para evitar asignaciones de mapas de bits redundantes.
  • Reciclar: Libera recursos de forma proactiva para permitir la reasignación de memoria para procesos activos.

La siguiente lista de tareas para desarrolladores puede ayudarte a optimizar el uso de memoria de mapas de bits.

Principio básico Área Descripción
Reducir Elimina mapas de bits duplicados Analiza los volcados de montón con el Generador de perfiles de memoria para detectar asignaciones de mapas de bits redundantes. Consulta la guía Cómo administrar la memoria del mapa de bits.
Aprovecha las bibliotecas de carga de imágenes Usa bibliotecas como Glide y Coil para automatizar el subprocesamiento, el almacenamiento en caché y la decodificación eficiente.
Implementa la reducción de muestreo Decodifica imágenes para que coincidan con las dimensiones del contenedor de la IU de destino en lugar de cargar recursos de resolución completa.
Usa RGB_565 para imágenes opacas Reduce el espacio en memoria en un 50% cambiando de ARGB_8888 a una configuración de 16 bits para imágenes sin transparencia.
Prioriza VectorDrawables Usa vectores para íconos y gráficos básicos para garantizar un escalamiento nítido con una sobrecarga de memoria mínima.
Optimiza la entrega de imágenes del servidor Configura las APIs de backend para entregar imágenes adaptadas a la densidad del dispositivo y a las dimensiones del contenedor de la IU.
Elimina los márgenes transparentes Evita asignar memoria para píxeles "invisibles" usando InsetDrawable o el padding de diseño en lugar de márgenes integrados. Consulta Cómo diseñar apps para Android con un buen rendimiento de memoria.
Reutilizar Configura tamaños de caché óptimos Adapta los límites de caché de memoria y disco según la RAM del dispositivo y la resolución de la pantalla. Consulta Cómo almacenar mapas de bits en caché.
Reciclar Borra recursos en segundo plano Implementa TRIM_MEMORY_BACKGROUND para borrar cachés y mejorar la supervivencia de los procesos durante la presión de la memoria del sistema.
Libera recursos cuando la IU está oculta Usa TRIM_MEMORY_UI_HIDDEN para liberar cachés de mapas de bits cuando la app ya no sea visible para el usuario.
Supervisa las fugas de memoria Usa LeakCanary y el Generador de perfiles de memoria para encontrar mapas de bits retenidos después de que se destruye su LifecycleOwner. Consulta Administra la memoria de tu app.