23

Getting an Exception in the BitmapFactory. Not sure what is the issue. (Well I can guess the issue, but not sure why its happening)

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

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

My code is pretty straight forward. I defined an XML layout w/ a default image. I try to load a bm on the SDCard (if present - it is). If not it shows the default image. Anyway.. Here is code :

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) {

It fails on the bm=Bitmap.createScaledBitmap any thoughts? I did some research on the forums, and it pointed to this post I just don't know why it is not working. Any help would be great! Thanks,

Chris.

Seki
  • 11,135
  • 7
  • 46
  • 70
Chrispix
  • 17,941
  • 20
  • 62
  • 70
  • How big is the original JPG image? There are some reports about this kind of error with two 6 Mpx files here: http://groups.google.com/group/android-developers/browse_thread/thread/0a6279680d1bd15e – schnaader Oct 19 '09 at 02:30

9 Answers9

13

inSampleSize is a good hint. But a fixed value often doesn't work fine, since large bitmaps from files usually are user files, which can vary from tiny thumbnails to 12MP images from the digicam.

Here's a quick and dirty loading routine. I know there's room for improvement, like a nicer coded loop, using powers of 2 for faster decoding, and so on. But it's a working start...

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;
}

Btw, in the newer APIs there are also lots of BitmapFactory.Option's for fitting the image to screen DPIs, but I'm not sure whether they really simplify anything. Using android.util.DisplayMetrics.density or simply a fixed size for less memory consumption seem to work better imho.

M. Schenk
  • 314
  • 3
  • 8
5

With reference to this link, please note the outOfMemory error can be solved by the following way:

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;
}
Danny Beckett
  • 20,529
  • 24
  • 107
  • 134
SampsonTan
  • 51
  • 1
  • 1
4

I ended up resizing the bitmap using the following code which seems to have resolved the issue.

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap = BitmapFactory.decodeFile(mPathName, options);
mrucci
  • 4,342
  • 3
  • 33
  • 35
Chrispix
  • 17,941
  • 20
  • 62
  • 70
4

Make sure to guard your bitmap creation from out of memory errors! With most platforms, android doesn't have much memory to play with and it runs out quickly with bitmaps. Also, make sure to manually recycle your bitmaps as much as possible, I've noticed that the garbage collection can be rather slow.

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 :(");
}
Ralphleon
  • 3,968
  • 5
  • 32
  • 34
  • Best way to do the GC? myFragileBitmap=null? – Chrispix Oct 24 '09 at 13:16
  • Doesn't always seem to do it, for some reason I normally set it to null after recycling however... I assume there exists some skia magic for bitmap clearing... – Ralphleon Oct 25 '09 at 01:20
4

http://code.google.com/p/android/issues/detail?id=8488

http://mobi-solutions.blogspot.com/2010/08/how-to-if-you-want-to-create-and.html

Steven Shih
  • 645
  • 1
  • 10
  • 22
  • 31
    I hate answers that are just links. Don't get me wrong, links are nice, but it sure feels lazy to just show a link with no explanation. – bugfixr Aug 04 '12 at 16:51
1

I think it is - what it it say it is. Your image is too big and since it is loaded in the stream when the memory is exhausted the exception is thrown. It's not even the question on how much memory you have overall but how much your particular Activity has available.

Bostone
  • 36,858
  • 39
  • 167
  • 227
  • The image is from a G1 phone camera. Image size was 2048x1536 apx 1.01MB – Chrispix Oct 19 '09 at 14:31
  • That's shoulf be OK but then, again - it's not the cumulative memory that counts but how much was allocated by system to your specific task. Can you verify that your code works with say 500K or 50K? – Bostone Oct 19 '09 at 15:59
1

use these options in decodefile. hope u can elemenate bitmap exceeds vm budget problem..

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]; 
Akshay
  • 2,506
  • 4
  • 34
  • 55
Sando
  • 1,893
  • 11
  • 29
  • 45
0

Have you checked the DDMS? With what I have been encountering, it's probably not the size of the images, because Android seems to handle large images pretty well. If you trace the heap with DDMS you may find that you happen to have a lot of free memory. 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. Unfortunately, with the exception it claims that it can't allocate some amount of bytes. Say 1M. If you take a look at the "free" line you will see that the largest block is >> 1M. There is something strange there that I can't figure out. It is not related even to the speed of swiping images. I saw in some thread that you can call "recycle" or so for bitmaps. I still don't see why it should help if the heap size is way above the taken size.

dcharles
  • 4,822
  • 2
  • 32
  • 29
Meymann
  • 2,520
  • 2
  • 28
  • 22
0

I got this error when i began to resize an image from 320x240 to something like 64x240 (downscale), then import into my project (since i wanted to improve rendering speed and it contained a lot of useless alpha regions until this point).

now the last answer makes much sense:

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.

I think this is what happened to me. Android automatically decodes drawables into bitmaps, (and then get stored on a heap, all on compilation time?)

i began seeing the error, when i used the smaller version of my image in runtime (i scale them up on runtime since i program a VGA-game with retro graphics, using BitmapFactory.decodeResource and Bitmap.createScaledBitmap).

it must be like Marve said: The Heap is not big enough in my case after shrinking my drawable/image and import it into my project.

I was able to get rid of my OutOfMemoryException when resizing the image back to a bigger size (320x240), which verifies the problem i guess?

calav3ra
  • 196
  • 1
  • 9