Bitmaps en Android

Tengo algunas preguntas sobre los objetos de bitmap y la memoria y su taxonomía general.

  1. ¿Qué es un bitmap nativo o en memoria?
  2. ¿En qué se diferencia la memoria de bitmap de la memoria Heap?

La memoria que respalda un objeto Bitmap se asigna utilizando código nativo ( malloc() ), en lugar de la new palabra clave Java. Esto significa que la memoria es administrada directamente por el sistema operativo, en lugar de por Dalvik.

La única diferencia real entre el montón nativo y el montón de Dalvik es que el montón de Dalvik es basura, y el nativo no.

Sin embargo, para estos fines, aquí no hay mucha diferencia. Cuando su objeto Bitmap obtiene basura recolectada, su destructor reciclará la memoria asociada en el montón nativo.

Fuente:

Aquí hay una sutileza importante: aunque los píxeles de bitmap se asignan en el montón nativo, algunos trucos especiales en Dalvik hacen que se contabilicen frente al montón de Java. Esto está hecho por dos razones:

(1) Para controlar la cantidad de memoria que una aplicación asigna esto. Sin la contabilidad, una aplicación podría asignar una gran cantidad de memoria (dado que el objeto Bitmap en sí mismo es muy pequeño pero puede retener una cantidad arbitrariamente grande de memoria nativa), extendiéndose más allá del límite de almacenamiento dynamic de 16MB o 24MB.

(2) Para ayudar a determinar cuándo GC. Sin la contabilidad, podría asignar y liberar referencias en decir 100 objetos de bitmap; el GC no se ejecutaría, porque estos objetos son pequeños, pero de hecho podrían representar una gran cantidad de megabytes de asignaciones reales que ahora no están siendo sometidas a un GC de manera oportuna. Al contabilizar estas asignaciones contra el montón de Java, el recolector de elementos no utilizados se ejecutará cuando crea que se está utilizando la memoria.

Tenga en cuenta que de muchas maneras esto es un detalle de implementación; es muy probable que pueda cambiar en el futuro, aunque este comportamiento básico se mantendría de alguna forma, ya que estas son características importantes para gestionar las asignaciones de mapas de bits.

Desde implementaciones en la naturaleza, he encontrado los siguientes dispositivos:

  • Dispositivos que limitan a 16 MiB de Java Heap (los mapas de bits son casi ilimitados).
  • Dispositivos que limitan a 16 MiB de (almacenamiento en bitmap nativo de Java +)
  • Dispositivos que limitan a 24 MiB de almacenamiento Java (los mapas de bits son casi ilimitados).
  • Dispositivos que limitan a 24 MiB de (almacenamiento en bitmap nativo de Java +)

24 MiB tiende a ser dispositivos de alta resolución, y se puede detectar con Runtime.getRuntime (). MaxMemory (). También hay dispositivos de 32MiB ahora, y algunos de los teléfonos rooteados tienen 64Mib por defecto. Previamente, me confundí varias veces tratando de descubrir qué estaba pasando. Creo que todos los dispositivos cuentan los mapas de bits en el límite del montón. Pero es muy difícil hacer generalizaciones generalizadas sobre la flota de Android.

Este es un problema MUY desagradable en Android, y muy confuso. Este límite y sus comportamientos están pobremente documentados, son complicados y extremadamente no intuitivos. También varían en los dispositivos y las versiones del sistema operativo, y tienen varios errores conocidos. Parte del problema es que los límites no son precisos: debido a la fragmentación del montón, alcanzará OOM mucho antes del límite real y debe dejar conservativamente un meg o dos de memoria intermedia. Peor aún, tengo varios dispositivos en los que hay una falla de segmentación nativa (100% un error en Android) que ocurre antes de que obtengas la excepción de OOM de Java, por lo que es doblemente importante no llegar nunca al límite ya que ni siquiera puedes atrapar el choque nativo. Para obtener más detalles sobre mis investigaciones, consulte esta publicación . En la misma publicación, explico cómo medir el uso contra el límite y evitar lockings.

El tamaño del montón de Java es Runtime.getRuntime (). TotalMemory ().

No existe una manera fácil de medir el tamaño del almacenamiento de bitmap nativo. El montón nativo general se puede medir con Debug.getNativeHeapAllocatedSize (), pero solo los mapas de bits cuentan hacia el límite (creo).

Podemos boost el tamaño del android:largeheap="true" dynamic usando android:largeheap="true" en su archivo de manifiesto. Esto resolverá tu problema.