android gallery imageview out-of-memory ddms

Android: OutofMemoryError: el tamaño del mapa de bits excede el presupuesto de VM sin ninguna razón por la que pueda ver



gallery imageview (5)

Creo que no hay nada especial en tu caso. Simplemente no hay suficiente memoria. No puede tener varios mapas de bits 600x800 en memoria, consumen demasiada memoria. Deberías guardarlos en SD y cargarlos en la memoria a pedido. Creo que eso es exactamente lo que haces.

Una cosa que debes tener en cuenta: DDMS muestra el consumo de la memoria del montón de Java. Pero también hay memoria nativa que no se muestra en DDMS. Y los mapas de bits, por lo que yo sé, se crean en la memoria nativa. Entonces DDMS es solo una mala herramienta para rastrear estos problemas de memoria. Solo necesita asegurarse de liberar su memoria, que Garbage Collector recopila las imágenes una vez que ya no las necesita.

Garbage Collector funciona en su propio horario. Es por eso que debes llamar al método Bitmap.recycle () en mapas de bits que ya no necesitas. Este método libera exactamente la memoria nativa que se te acaba. De esta manera no depende de GC y puede liberar la mayor cantidad de memoria lo antes posible.

En primer lugar, debe asegurarse de no filtrar mapas de bits.

Aquí hay una buena post sobre las asignaciones de memoria, puede ayudarte a cavar más profundo

Tengo una excepción OutOfMemory con una galería de más de 600x800 píxeles JPEG.

El entorno

He estado utilizando Galería con imágenes JPG de alrededor de 600x800 píxeles.

Como mi contenido puede ser un poco más complejo que las imágenes, configuré cada vista como RelativeLayout que envuelve ImageView con el JPG.

Para "acelerar" la experiencia del usuario, tengo un caché simple de 4 ranuras que capta previamente (en un looper) aproximadamente 1 imagen a la izquierda y 1 imagen a la derecha de la imagen mostrada y las mantiene en un HashMap de 4 ranuras.

La plataforma

Estoy usando AVD de 256 RAM y 128 Heap Size, con una pantalla de 600x800. También ocurre en un destino Entourage Edge, excepto que con el dispositivo es más difícil de depurar.

El problema

He estado recibiendo una excepción:

OutofMemoryError: bitmap size exceeds VM budget

Y sucede cuando buscamos la quinta imagen. Intenté cambiar el tamaño de la memoria caché de mi imagen, y sigue siendo la misma.

Lo extraño: no debería haber un problema de memoria

Para asegurarme de que el límite del montón está muy lejos de lo que necesito, he definido una matriz ficticia de 8MB al principio, y la dejé sin referencia para que se envíe de inmediato. Es un miembro del hilo de actividad y se define como lo siguiente

static { @SuppressWarnings("unused") byte dummy[] = new byte[ 8*1024*1024 ]; }

El resultado es que el tamaño del montón es de casi 11 MB y todo es gratis. Tenga en cuenta que he agregado ese truco después de que comenzó a fallar. Hace que OutOfMemory sea menos frecuente.

Ahora, estoy usando DDMS. Justo antes del accidente (no cambia mucho después del bloqueo), DDMS muestra:

ID Heap Size Allocated Free %Used #Objects 1 11.195 MB 2.428 MB 8.767 MB 21.69% 47,156

Y en la tabla de detalles se muestra:

Type Count Total Size Smallest Largest Median Average free 1,536 8.739MB 16B 7.750MB 24B 5.825KB

El bloque más grande es 7.7MB. Y sin embargo, el LogCat dice:

ERROR/dalvikvm-heap(1923): 925200-byte external allocation too large for this process.

Si le importa la relación entre la mediana y el promedio, es plausible suponer que la mayoría de los bloques disponibles son muy pequeños. Sin embargo, hay un bloque lo suficientemente grande para el mapa de bits, es 7.7M. ¿Cómo es que todavía no es suficiente?

Nota: Grabé un rastro de montón. Al observar la cantidad de datos asignados, no parece que se hayan asignado más de 2M. Coincide con el informe de memoria libre por DDMS.

  • ¿Podría ser que experimente algún problema como la fragmentación de montón?
  • ¿Cómo resuelvo / soluciono el problema?
  • ¿El montón se comparte con todos los hilos?
  • ¿Podría ser que interpreto la lectura de DDMS de una manera incorrecta, y realmente no hay un bloque de 900K para asignar? Si es así, ¿alguien puede decirme dónde puedo ver eso?

Muchas gracias

Meymann


Ha habido mucho tiempo desde que pregunté eso.

La respuesta se debe dividir en 2 partes: Pre-Gingerbread: solo usa imágenes pequeñas, use submuestreo, tal vez una foto de tamaño de pantalla, y espere para siempre. Intenta asegurarte de no asignar elementos pequeños que no puedas liberar antes de obtener un mapa de bits. Antes del jengibre, la memoria para los bmps tenía que ser condicional, y no se contaba en la memoria de la máquina virtual. Siempre mire el logcat. Vea una conferencia sobre la memoria de Google IO 2011. Publicar Ginger es más fácil. Desde Honeycomb, incluso se cuentan los mapas de bits en su área de Java. No hay área jni. Siempre use reciclaje para mapas de bits que no necesita. No esperes el GC.


La pregunta fue hecha en 2010, cuando Froyo estaba fresco. Tantas cosas pasaron desde entonces. Antes de 3.0, se asignaron mapas de bits en JNI. La memoria no se muestra en las estadísticas de Dalvik. Ya no tiene que ser monolítico. Antes de 2.3, las estadísticas de memoria para JNI no estaban disponibles (llamadas de descodificación de mapas de bits JNI) en logcat. 4.4 evacuó más espacio. 5.0 el Big Bang de Arte. En 2010, Nexus One era de gama alta, con menos de 300 MB. El presupuesto para una aplicación fue de alrededor de 16 MB. Hoy en día, hay cerca de 8 veces esa memoria.



También me enfrenté a un problema similar hace un par de semanas y lo resolví reduciendo las imágenes hasta el punto óptimo. He escrito un enfoque completo en mi blog here y he cargado un proyecto de muestra completo con el código propenso OOM vs código OOM Proof here .