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

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


El entorno

He estado usando Galería con imágenes JPG alrededor de 600×800 píxeles.

Dado que mi contenido puede ser un poco más complejo que sólo imágenes, he configurado cada vista para ser un RelativeLayout que envuelve ImageView con el JPG.

Con el fin de "acelerar" la experiencia del usuario que tengo una caché simple de 4 ranuras que prefetches (en un looper) alrededor de 1 imagen a la izquierda y 1 imagen a la derecha a la imagen mostrada y los mantiene en un 4 HashMap ranura.

La plataforma

Estoy utilizando AVD de 256 RAM y 128 Heap tamaño, con una pantalla de 600×800. También ocurre en un destino de 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 se busca la quinta imagen. He intentado cambiar el tamaño de mi caché de imágenes, y sigue siendo el mismo.


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

Con el fin de asegurarse de que el límite de montón está muy lejos de lo que necesito, he definido un dummy 8MB matriz en el principio, y dejó sin referencia por lo que es inmediatamente despachado. Es un miembro del hilo de actividad y se define como siguiente

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

El resultado es que el tamaño del montón es casi 11 MB y todo es gratis. Nota He añadido ese truco después de que empezó a estrellarse. Hace que OutOfMemory sea menos frecuente.

Ahora, estoy usando DDMS. Justo antes de la caída (no cambia mucho después del accidente), 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 te importa la relación de la mediana y el promedio, es plausible asumir 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é una traza de montón. Al mirar la cantidad de datos asignados, no se siente como más de 2 millones se asigna. Hace coincidir el informe de memoria libre por DDMS.


  • ¿Podría ser que experimente algún problema como heap-fragmentación?
  • ¿Cómo soluciono el problema?
  • ¿El montón está compartido con todos los subprocesos?
  • ¿Podría ser que interpretar la lectura DDMS de una manera incorrecta, y realmente no hay 900K bloque para asignar? Si es así, ¿puede alguien decirme por favor dónde puedo ver eso?

Muchas gracias

Meymann

Creo que no hay nada especial en tu caso. Simplemente no hay suficiente memoria. No puede tener varios mapas de bits 600×800 en memoria, consumen demasiada memoria. Debe guardarlos en SD y cargarlos en memoria cuando lo solicite. Creo que eso es exactamente lo que haces.

Una cosa que debe tener en cuenta: DDMS muestra el consumo de memoria java heap. Pero también hay memoria nativa que no se muestra en DDMS. Y mapas de bits por lo que yo entiendo son creados en la memoria nativa. Así que DDMS es sólo una mala herramienta para rastrear estos problemas de memoria. Sólo tienes que estar seguro de que liberas tu memoria, que las imágenes son recogidas por Garbage Collector después de que ya no las necesites.

Garbage Collector trabaja en su propio calendario. Es por eso que debe llamar al método Bitmap.recycle () en mapas de bits que ya no necesita. Este método libera exactamente la memoria nativa que se ejecuta fuera de. De esta manera usted no depende de GC y puede liberar la mayor parte de la memoria lo antes posible.

En primer lugar debe asegurarse de que no se filtren bitmaps.

Aquí hay un buen post sobre las asignaciones de memoria, puede ayudarte a profundizar

¿No está seguro si es una opción para usted, pero usted ha intentado imágenes del supersampling Extraño fuera del problema de la memoria mientras que carga una imagen a un objeto del mapa de bits ?

También me enfrenté a un par de cuestiones similares de semanas atrás y lo resolví mediante la reducción de las imágenes hasta el punto óptimo. He escrito el acercamiento completo en mi blog aquí y uploaded el proyecto completo de la muestra con código propenso de OOM contra código de la prueba de OOM aquí .

Ha habido mucho tiempo desde que le pregunté eso.

La respuesta debe dividirse en 2 partes: Pre-Gingerbread: solo usa imágenes pequeñas, usa submuestreo, tal vez una foto de tamaño de pantalla, y espere para siempre. Intente cerciorarse de no asignar los artículos minúsculos que usted no puede liberar antes de conseguir un mapa de bits. Pre-Ginger, la memoria para bmps tenía que ser contonea, y no se contaba en la memoria VM. Mira siempre el logcat. Ver una conferencia sobre la memoria de Google IO 2011. Post Ginger es más fácil. Desde Honeycomb, bitmaps son incluso contados en su área de java. No hay área de jni. Siempre use reciclar para mapas de bits que no necesita. No espere por el GC.

La pregunta fue hecha en 2010, cuando Froyo estaba fresco. Tantas cosas pasaron desde entonces. Antes de 3.0, mapas de bits se asignaron en JNI. La memoria no se mostró 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 (decodificación de mapa de bits llamadas JNI) en logcat. 4.4 evacuó más espacio. 5.0 el big bang del Art. En 2010, Nexus One era de gama alta, con menos de 300 MB. El presupuesto para una aplicación era de unos 16 MB. Ahora días, hay alrededor de 8 veces esa memoria.

  • Android - Vista de imagen en el centro en toda la resolución de la pantalla
  • Cómo obtener la imagen de url sitio web en imageview en android
  • Vista de imagen con esquinas redondeadas después de escalar con ScaleType.CenterCrop
  • Dibujar un rectángulo detrás de ImageView personalizado que no anima
  • Android - Lienzo negro cuando se utiliza Flood-Fill
  • Cómo añadir texto a ImageView en Android
  • Establecer la imagen del url a la vista de la imagen
  • Hacer fondo transparente de los iconos de Android en eclipse
  • ImageView en el diseño de android XML con layout_height = "wrap_content" tiene relleno superior e inferior
  • Galería de imágenes con ViewPager + zoom en ImageViews
  • Android setX () y setY () comportándose de manera extraña
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.