2009-10-19 20 views
22

Obteniendo una excepción en BitmapFactory. No estoy seguro de cuál es el problema. (Bueno, puedo adivinar el problema, pero no estoy seguro de por qué está sucediendo)OutofMemoryError: el tamaño del mapa de bits excede el presupuesto de la VM (Android)

ERROR/AndroidRuntime(7906): java.lang.OutOfMemoryError: bitmap size exceeds VM budget 

ERROR/AndroidRuntime(7906):  at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:295)

Mi código es bastante directo. Definí un diseño XML con una imagen predeterminada. Intento cargar un bm en la tarjeta SD (si está presente, lo es). Si no, muestra la imagen predeterminada. De todos modos .. Aquí está el código:

public class showpicture extends Activity { 
    public void onCreate(Bundle savedInstanceState) { 

     /** Remove menu/status bar **/ 
     requestWindowFeature(Window.FEATURE_NO_TITLE); 
     final Window win = getWindow(); 
     win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); 

      Bitmap bm; 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.showpicture); 
      try { 
     ImageView mImageButton = (ImageView)findViewById(R.id.displayPicture); 
     bm = Bitmap.createScaledBitmap(BitmapFactory.decodeFile("/sdcard/dcim/Camera/20091018203339743.jpg"),100, 100, true); 
     parkImageButton.setImageBitmap(bm); 
     } 
     catch (IllegalArgumentException ex) { 
      Log.d("MYAPP",ex.getMessage()); 
     } 
      catch (IllegalStateException ex) { 

Se produce un error en la bm=Bitmap.createScaledBitmap alguna idea? Investigué un poco en los foros y señaló this post . No sé por qué no funciona. ¡Cualquier ayuda sería genial! Gracias,

Chris.

+0

¿Qué tan grande es la imagen JPG original? Hay algunos informes sobre este tipo de error con dos archivos de 6 Mpx aquí: http://groups.google.com/group/android-developers/browse_thread/thread/0a6279680d1bd15e – schnaader

Respuesta

1

Creo que es - lo que dice que es. Su imagen es demasiado grande y, dado que se carga en la secuencia cuando se agota la memoria, se lanza la excepción. Ni siquiera es cuestión de cuánta memoria tienes en total, sino de cuánto tiene disponible tu actividad particular.

+0

La imagen es de una cámara de un teléfono G1. El tamaño de la imagen era 2048x1536 apx 1.01MB – Chrispix

+0

Eso está bien, pero una vez más, no es la memoria acumulativa lo que cuenta, sino cuánto fue asignado por el sistema a su tarea específica. ¿Puedes verificar que tu código funciona con decir 500K o 50K? – Bostone

4

Terminé cambiando el tamaño del mapa de bits usando el siguiente código que parece haber resuelto el problema.

BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inSampleSize = 8; 
Bitmap preview_bitmap = BitmapFactory.decodeFile(mPathName, options); 
4

¡Asegúrese de proteger la creación de su mapa de bits de errores de memoria! Con la mayoría de las plataformas, Android no tiene mucha memoria para jugar y se ejecuta rápidamente con bitmaps. Además, asegúrese de reciclar manualmente sus mapas de bits tanto como sea posible, me he dado cuenta de que la recolección de basura puede ser bastante lenta.

try{    
    Bitmap myFragileBitmap = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888); 
} 
catch(IllegalArgumentException e){ 
    Log.e(TAG,"Illegal argument exception."); 
} 
catch(OutOfMemoryError e){ 
    Log.e(TAG,"Out of memory error :("); 
} 
+0

¿La mejor manera de hacer el GC? myFragileBitmap = null? – Chrispix

+0

No parece que siempre lo haga, por alguna razón, normalmente lo configuro como nulo después de reciclarlo ... Supongo que existe algo de magia de skia para borrar los mapas de bits ... – Ralphleon

13

inSampleSize es una buena pista. Pero un valor fijo a menudo no funciona bien, ya que los grandes mapas de bits de los archivos generalmente son archivos de usuario, que pueden variar desde diminutas miniaturas hasta imágenes de 12MP desde la cámara digital.

Aquí hay una rutina de carga rápida y sucia. Sé que hay margen de mejora, como un bucle codificado más agradable, utilizando potencias de 2 para una decodificación más rápida, y así sucesivamente. Pero es un comienzo de trabajo ...

public static Bitmap loadResizedBitmap(String filename, int width, int height, boolean exact) { 
    Bitmap bitmap = null; 
    BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeFile(filename, options); 
    if (options.outHeight > 0 && options.outWidth > 0) { 
     options.inJustDecodeBounds = false; 
     options.inSampleSize = 2; 
     while ( options.outWidth/options.inSampleSize > width 
       && options.outHeight/options.inSampleSize > height) { 
      options.inSampleSize++; 
     } 
     options.inSampleSize--; 

     bitmap = BitmapFactory.decodeFile(filename, options); 
     if (bitmap != null && exact) { 
      bitmap = Bitmap.createScaledBitmap(bitmap, width, height, false); 
     } 
    } 
    return bitmap; 
} 

Por cierto, en el API más nuevos también hay un montón de BitmapFactory.Option para el montaje de la imagen a la pantalla inhaladores de polvo seco, pero no estoy seguro de si realmente simplifican nada. Usar android.util.DisplayMetrics.density o simplemente un tamaño fijo para reducir el consumo de memoria parece funcionar mejor.

0

¿Has comprobado el DDMS? Con lo que he estado encontrando, probablemente no sea del tamaño de las imágenes, porque Android parece manejar imágenes grandes bastante bien. Si rastrea el montón con DDMS, es posible que tenga mucha memoria libre. Puede "ampliar" su montón añadiendo esta

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

a su código, para forzar el montón de expandirse. Puede hacerlo un poco menos frecuente. Desafortunadamente, con la excepción, afirma que no puede asignar una cierta cantidad de bytes. Digamos 1M. Si echas un vistazo a la línea "libre", verás que el bloque más grande es >> 1M. Hay algo extraño allí que no puedo entender. No está relacionado ni siquiera con la velocidad de deslizamiento de imágenes. Vi en un hilo que puede llamar "reciclar" más o menos para bitmaps. Todavía no veo por qué debería ayudar si el tamaño del montón está muy por encima del tamaño tomado.

1

usar estas opciones en decodefile. esperanza u puede elemenate mapa de bits excede vm problema del presupuesto ..

BitmapFactory.Options bfOptions=new BitmapFactory.Options(); 

bfOptions.inDither=false;   //Disable Dithering mode 
bfOptions.inPurgeable=true;  //Tell to gc that whether it needs free memory, the Bitmap can be cleared 
bfOptions.inInputShareable=true; //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future 
bfOptions.inTempStorage=new byte[32 * 1024]; 
+0

Este método ayudó, gracias amigo! :RE – Xarialon

0

Tengo este error cuando empecé a cambiar el tamaño de una imagen de 320x240 a algo así como 64x240 (descendente de la escala), y luego importar en mi proyecto (ya que quería mejorar velocidad de renderizado y contenía muchas regiones alfa inútiles hasta este punto).

ahora la última respuesta tiene mucho sentido:

You can "expand" your heap by adding this static { @SuppressWarnings("unused") byte dummy[] = new byte[ 8*1024*1024 ]; } to your code, to force the heap to expand. It may make it a bit less frequent.

Creo que esto es lo que me pasó. Android decodifica automáticamente dibujables en mapas de bits, (y luego se almacena en un montón, todo el tiempo de compilación?)

comencé a ver el error, cuando utilicé la versión más pequeña de mi imagen en tiempo de ejecución (los amplié en tiempo de ejecución ya que programo un juego VGA con gráficos retro, usando BitmapFactory.decodeResource y Bitmap.createScaledBitmap).

debe ser como Marve dijo: The Heap no es lo suficientemente grande en mi caso después de reducir mi dibujo/imagen e importarlo a mi proyecto.

Pude deshacerme de mi OutOfMemoryException al cambiar el tamaño de la imagen a un tamaño mayor (320x240), lo que verifica el problema, supongo?

5

Con referencia a la presente link, tenga en cuenta el error outOfMemory puede ser resuelto mediante la siguiente manera:

public Bitmap decodeFile(String filePath) { 

Bitmap bitmap = null; 
BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inPurgeable = true; 

try { 
BitmapFactory.Options.class.getField("inNativeAlloc").setBoolean(options,true); 

} catch (IllegalArgumentException e) { 
    e.printStackTrace(); 
} catch (SecurityException e) { 
    e.printStackTrace(); 
} catch (IllegalAccessException e) { 
    e.printStackTrace(); 
} catch (NoSuchFieldException e) { 
    e.printStackTrace(); 
} 

if(filePath != null) 
{ 
    bitmap = BitmapFactory.decodeFile(filePath, options);    
} 

return bitmap; 
} 
Cuestiones relacionadas