suficiente solucionar restaurar que problema para pagina memoria insuficiente hay funcionen esta error equipo como abrir android bitmap heap out-of-memory

android - solucionar - Sugerencias para evitar el error de memoria insuficiente de mapas de bits



memoria insuficiente windows 10 2017 (6)

Al reducir / Escalar el tamaño de la imagen puede deshacerse de la Excepción de falta de memoria. Pruebe esto

BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 6; Bitmap receipt = BitmapFactory.decodeFile(photo.toString(),options); //From File You can customise on your needs.

Estoy trabajando en una aplicación de Android. La aplicación tiene una vista que contiene mucha imagen. Tuve un error, trataré de dar tanta información como sea posible con la esperanza de que alguien pueda darme algunas sugerencias.

La aplicación funcionaba muy bien en todas las pruebas locales. Sin embargo, recibí muchas caídas de usuarios: java.lang.OutOfMemoryError: bitmap size exceeds VM budget

Este es el rastro de la pila

0 java.lang.OutOfMemoryError: bitmap size exceeds VM budget 1 at android.graphics.Bitmap.nativeCreate(Native Method) 2 at android.graphics.Bitmap.createBitmap(Bitmap.java:507) 3 at android.graphics.Bitmap.createBitmap(Bitmap.java:474) 4 at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:379) 5 at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:498) 6 at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:473) 7 at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336) 8 at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:359) 9 at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:385)

Mi mayor problema es que no pude reproducir el problema localmente incluso en dispositivos antiguos.

He implementado muchas cosas para tratar de resolver esto:

  1. No hay pérdidas de memoria : me aseguré de que no haya pérdidas de memoria. Eliminé las vistas cuando no las necesito. También reciclé todos los mapas de bits y me aseguré de que el recolector de basura funcionara como debería. E implementé todos los pasos necesarios en el método onDestroy()
  2. Tamaño de imagen escalado correctamente : antes de obtener la imagen, obtengo su dimensión y calculo inSampleSize .
  3. Tamaño de pila : también detecto el tamaño de Max Heap antes de obtener la imagen y me aseguro de que haya suficiente espacio. Si no hay suficiente, reescaneo la imagen en consecuencia.

Código para calcular el tamaño de muestra correcto

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if(height > reqHeight || width > reqWidth) { if(width > height) { inSampleSize = Math.round((float) height / (float) reqHeight); } else { inSampleSize = Math.round((float) width / (float) reqWidth); } } return inSampleSize; }

Código para obtener el mapa de bits

// decodes image and scales it to reduce memory consumption private static Bitmap decodeFile(File file, int newWidth, int newHeight) {// target size try { Bitmap bmp = MediaStore.Images.Media.getBitmap(getContext().getContentResolver(), Uri.fromFile(file)); if(bmp == null) { // avoid concurrence // Decode image size BitmapFactory.Options option = new BitmapFactory.Options(); // option = getBitmapOutput(file); option.inDensity = res.getDisplayMetrics().densityDpi < DisplayMetrics.DENSITY_HIGH ? 120 : 240; option.inTargetDensity = res.getDisplayMetrics().densityDpi; if(newHeight > 0 && newWidth > 0) option.inSampleSize = calculateInSampleSize(option, newWidth, newWidth); option.inJustDecodeBounds = false; byte[] decodeBuffer = new byte[12 * 1024]; option.inTempStorage = decodeBuffer; option.inPurgeable = true; option.inInputShareable = true; option.inScaled = true; bmp = BitmapFactory.decodeStream(new FileInputStream(file), null, option); if(bmp == null) { return null; } } else { int inDensity = res.getDisplayMetrics().densityDpi < DisplayMetrics.DENSITY_HIGH ? 120 : 240; int inTargetDensity = res.getDisplayMetrics().densityDpi; if(inDensity != inTargetDensity) { int newBmpWidth = (bmp.getWidth() * inTargetDensity) / inDensity; int newBmpHeight = (bmp.getHeight() * inTargetDensity) / inDensity; bmp = Bitmap.createScaledBitmap(bmp, newBmpWidth, newBmpHeight, true); } } return bmp; } catch(Exception e) { Log.e("Error calling Application.decodeFile Method params: " + Arrays.toString(new Object[]{file }), e); } return null; }

Código para calcular el tamaño de la imagen en función del tamaño del Heap para dispositivos más antiguos

private void calculateImagesSize() { // only for android older than HoneyComb that does not support large heap if(Build.VERSION.SDK_INT < Constants.HONEYCOMB) { long maxHeapSize = Runtime.getRuntime().maxMemory(); long maxImageHeap = maxHeapSize - 10485760; if(Application.getResource().getDisplayMetrics().densityDpi >= DisplayMetrics.DENSITY_XHIGH) { maxImageHeap -= 12 * 1048576; } if(maxImageHeap < (30 * 1048576)) { int screenHeight = Math.min(Application.getResource().getDisplayMetrics().heightPixels, Application.getResource() .getDisplayMetrics().widthPixels); long maxImageSize = maxImageHeap / 100; long maxPixels = maxImageSize / 4; long maxHeight = (long) Math.sqrt(maxPixels / 1.5); if(maxHeight < screenHeight) { drawableHeight = (int) maxHeight; drawableWidth = (int) (drawableHeight * 1.5); } } } }

Creo que el problema está en el Heap, quizás a veces el sistema operativo no permita que la aplicación use el maxheapsize. Además, mi mayor problema es que no pude reproducir el problema, así que cuando pruebo una solución, tengo que esperar un poco para ver si los usuarios siguen recibiendo el error.

¿Qué más podría tratar de evitar problemas de falta de memoria? Cualquier sugerencia sería muy apreciada. Muchas gracias



Hola, debes decodificar el archivo. para este intento con el siguiente método.

public static Bitmap new_decode(File f) { // decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; o.inDither = false; // Disable Dithering mode o.inPurgeable = true; // Tell to gc that whether it needs free memory, // the Bitmap can be cleared o.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 try { BitmapFactory.decodeStream(new FileInputStream(f), null, o); } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } // Find the correct scale value. It should be the power of 2. final int REQUIRED_SIZE = 300; int width_tmp = o.outWidth, height_tmp = o.outHeight; int scale = 1; while (true) { if (width_tmp / 1.5 < REQUIRED_SIZE && height_tmp / 1.5 < REQUIRED_SIZE) break; width_tmp /= 1.5; height_tmp /= 1.5; scale *= 1.5; } // decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); // o2.inSampleSize=scale; o.inDither = false; // Disable Dithering mode o.inPurgeable = true; // Tell to gc that whether it needs free memory, // the Bitmap can be cleared o.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 // return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); try { // return BitmapFactory.decodeStream(new FileInputStream(f), null, // null); Bitmap bitmap= BitmapFactory.decodeStream(new FileInputStream(f), null, null); System.out.println(" IW " + width_tmp); System.out.println("IHH " + height_tmp); int iW = width_tmp; int iH = height_tmp; return Bitmap.createScaledBitmap(bitmap, iW, iH, true); } catch (OutOfMemoryError e) { // TODO: handle exception e.printStackTrace(); // clearCache(); // System.out.println("bitmap creating success"); System.gc(); return null; // System.runFinalization(); // Runtime.getRuntime().gc(); // System.gc(); // decodeFile(f); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } }


Si desea evitar OOM, puede capturar OOM y aumentar el tamaño de muestra hasta que la imagen se pueda resolver:

private Bitmap getBitmapSafely(Resources res, int id, int sampleSize) { // res = context.getResources(), id = R.drawable.yourimageid Bitmap bitmap = null; BitmapFactory.Options options = new BitmapFactory.Options(); options.inPurgeable = true; options.inSampleSize = sampleSize; try { bitmap = BitmapFactory.decodeResource(res, id, options); } catch (OutOfMemoryError oom) { Log.w("ImageView", "OOM with sampleSize " + sampleSize, oom); System.gc(); bitmap = getBitmapSafely(res, id, sampleSize + 1); } return bitmap; }

Espero eso ayude.

No es adecuado detectar el error, solo una solución.


en realidad el problema es con el desarrollo OS. En Android, a diferencia de iOS, las personas de Google desarrollan esto en función de la resolución de la cámara. Los mapas de bits ocupan mucha memoria, especialmente para imágenes ricas como fotografías. Diferentes cámaras capturan imágenes con diferentes píxeles (diferentes móviles tienen una capacidad de píxel de cámara diferente). Aquí en Android, basado en esos píxeles, solo la imagen capturada tomará memoria. así que obviamente una imagen de alta resolución no será cargada por un teléfono con baja capacidad de píxeles. En Android OS asigna más de 16 MB a cada aplicación. Si la imagen cargada tarda más que esto, java.lang.OutofMemoryError: el tamaño del mapa de bits excede el presupuesto de la VM y la aplicación se bloquea. refiérete a este developer.android.com/training/displaying-bitmaps/index.html


solo use esta función para decodificar ... esta es la solución perfecta para su error ... porque también estoy obteniendo el mismo error y obtuve esta solución ...

public static Bitmap decodeFile(File f,int WIDTH,int HIGHT){ try { //Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(f),null,o); //The new size we want to scale to final int REQUIRED_WIDTH=WIDTH; final int REQUIRED_HIGHT=HIGHT; //Find the correct scale value. It should be the power of 2. int scale=1; while(o.outWidth/scale/2>=REQUIRED_WIDTH && o.outHeight/scale/2>=REQUIRED_HIGHT) scale*=2; //Decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize=scale; return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); } catch (FileNotFoundException e) {} return null; }