Suggestions to avoid bitmap Out of Memory error
Solution 1
just use this function to decode...this is perfect solution for your error..because i also getting same error and i got this solution..
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;
}
Solution 2
Hi you have to decode the file . for this try with the following method.
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;
}
}
Solution 3
By Reducing/Scale size of the Image you can get rid out of the Out of Memory Exception, Try this
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 6;
Bitmap receipt = BitmapFactory.decodeFile(photo.toString(),options); //From File You can customise on your needs.
Y2theZ
Updated on October 20, 2021Comments
-
Y2theZ over 2 years
I am working on an android application. The application has a view containing lots of image. I had an error, I will try to give as much information as possible hoping someone can give me some suggestions.
The application was working great on all the local testings. However, I received lots of crashes from users:
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
This is the stack trace
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)
My biggest problem is that I was not able to reproduce the issue locally even on old devices.
I have implemented lots of things to try to resolve this:
- No memory leaks: I made sure there is no memory leaks at all. I removed the views when I dont need them. I also recycled all the bitmaps and made sure the garbage collector is working as it should. And I implemented all the necessary steps in the
onDestroy()
method - Image size scaled correctly: Before getting the image I get its dimension and calculate the
inSampleSize
. - Heap size: I also detect the Max Heap size before getting the image and make sure there is enough space. If there is not enough I rescale the image accordingly.
Code to calculate the correct inSampleSize
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; }
Code to get the bitmap
// 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; }
Code to calculate image size based on Heap size for older devices
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); } } } }
I think the problem is with the Heap, maybe sometimes the os doesn't allow the application to use the maxheapsize. Also my biggest problem is that I was not able to reproduce the issue, so when I try a fix I have to wait a little to see if users are still getting the error.
What more could I try to avoid Out of memory issues? Any suggestions would be greatly appreciated. Thanks a lot
- No memory leaks: I made sure there is no memory leaks at all. I removed the views when I dont need them. I also recycled all the bitmaps and made sure the garbage collector is working as it should. And I implemented all the necessary steps in the
-
Y2theZ over 11 yearsHi, thank you for your suggestion but I am actually doing the same thing but with more advanced check. I had the exact code you have but was having a crash. so I modified it to take in consideration more advanced stuff. But the logic in your code is present in mine. Thanks
-
Mehul Ranpara over 11 yearshave you used this function?
-
Y2theZ over 11 yearsyes I used it first. but I got the OutOfMemoryError so I modified it to what I have today. it reduced the error but it is still appearing
-
Mehul Ranpara over 11 yearswhat is the size of your image ?
-
Y2theZ over 11 yearsusually it is 320x320. but the problem is not with the size of the image because I am scalling it to a very low resolution if needed (When calculating the available heap size)
-
Melllvar over 9 yearsAn
OutOfMemoryError
cannot be caught -
Euporie over 9 years@Melllvar I tested these code and I have really caught the OOM. Do you mean is not suitable to catch the OOM?
-
Melllvar over 9 yearsOK, so I'm seeing a lot of conflicting information (e.g. see this post). I myself have had unrecoverable crashes inside
try/catch(OutOfMemoryError)
, but what I'm seeing suggests that this is more or less a matter of luck (e.g. it may be possible, but if you do recover from an error, there is a chance that the error will leave the program in an indeterminate state; therefore the crash will occur no matter what). In any case, your solution may work (I stand corrected) - just not always. -
Euporie over 9 years@Melllvar thanks, I need to learn more about the differences betweeen exception and error, and I have edited my post.
-
Yoann Hercouet over 9 yearsYou can still get the exception if the image provided is very big.
-
itsrajesh4uguys about 9 yearsThanks @MuhammedRefaat...:)
-
Avi Levin over 8 yearsI don't like the System.gc() solution. try to find why it's happening, look for memory leak and so one.
-
Roman Nazarevych over 8 yearswhy not to use just
o2.inSampleSize = Math.max(o.outHeight,o.outWidth)/imageMaxSize;
instead ofwhile(o.outWidth/scale/2>=REQUIRED_WIDTH && o.outHeight/scale/2>=REQUIRED_HIGHT) scale*=2;
According to documentation "Note: the decoder uses a final value based on powers of 2, any other value will be rounded down to the nearest power of 2." so android will do the rounding automatically. -
FindOut_Quran over 8 years
OutOfMemory
most of time never getscatch
ed. Just crashes the app. -
Abhijit Chakra over 7 yearsHere you will lose quality