Organizational Research By

Surprising Reserch Topic

Question:OutOfMemoryError of Bitmap in Android


I am developing one demo application in which I am playing so many images(Bitmaps). I am using Global Bitmap object for display same image in to more than one Activity. But using that I am geting OutOfMemoryError while I am trying to create Bitmap using Bitmap.createBitmap(...). I tried using this code but still I am getting same error and it is crashing my application and through the OutOfMemoryError.

I am stuck on this. Can anyone has any solution to avoid this.??

Thanks in advance.

I am getting bitmap after cropping the image so that I am using below code for decode the bitmap size.

public static Bitmap loadFromBitmap( Context context, Bitmap b, int maxW, int maxH ) throws IOException {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        Bitmap bitmap = null;
        options.inScaled = false;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        options.inJustDecodeBounds = true;
        BufferedInputStream stream = null;
        ByteArrayOutputStream outstream = new ByteArrayOutputStream();
        b.compress(CompressFormat.JPEG, 100, outstream);
        InputStream is = new java.io.ByteArrayInputStream(outstream.toByteArray());

        stream = new BufferedInputStream(is, 16384 );
        if ( stream != null ) {
            options.inSampleSize = calculateInSampleSize( options, maxW, maxH );
            stream = null;
            stream = new BufferedInputStream(is, 16384 );
        } else {
            return null;
        }
        options.inDither = false;
        options.inJustDecodeBounds = false;
        options.inPurgeable = true;
        bitmap = BitmapFactory.decodeStream( stream, null, options );
        if ( bitmap != null ) bitmap = BitmapUtils.resizeBitmap( bitmap, maxW, maxH );
        return bitmap;
    }

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

            // Calculate ratios of height and width to requested height and width
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);

            // Choose the smallest ratio as inSampleSize value, this will guarantee
            // a final image with both dimensions larger than or equal to the
            // requested height and width.
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }

        return inSampleSize;
    }

Error:

02-21 15:32:31.160: E/AndroidRuntime(2951): FATAL EXCEPTION: main
02-21 15:32:31.160: E/AndroidRuntime(2951): java.lang.OutOfMemoryError
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:483)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:351)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:374)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:404)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.app.Activity.performCreate(Activity.java:4465)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1092)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1924)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1985)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.app.ActivityThread.access$600(ActivityThread.java:127)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1151)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.os.Handler.dispatchMessage(Handler.java:99)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.os.Looper.loop(Looper.java:137)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at android.app.ActivityThread.main(ActivityThread.java:4447)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at java.lang.reflect.Method.invokeNative(Native Method)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at java.lang.reflect.Method.invoke(Method.java:511)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
02-21 15:32:31.160: E/AndroidRuntime(2951):     at dalvik.system.NativeStart.main(Native Method)

asked Sep 13, 2013 in ANDROID by rajesh
edited Sep 12, 2013
0 votes
46 views



Related Hot Questions

6 Answers

0 votes

Ah - the many wonderful battles one may have with Google's implementation of bitmap handling in Android.

I would tend to do some memory profiling anytime I hit the roof with memory - very often (although not always) it is because one is doing something wrong (i.e., unexpectedly memory intensive). Just browsing the code, I am a little bit puzzled by the need to force the code through three streams, just to end up with a bitmap again. I feel as if I'm missing some information for me to make sense of this, but I'd definitely take a look at just how much memory you're allocating in each of those steps if I were you (heap dump -> hprof-conv -> memory analyzer is your friend).

However, I suspect that what you may be looking for is BitmapRegionDecoder. I actually only recently discovered this myself, but I think it does pretty much exactly what you are after - allows you to decode a region from a bitmap (inputstream) without loading the entire bitmap into memory (you can also get the width/height). Only downside is that it is Android 2.3.3+ only, but these days that >90% of the market so that should not be a huge problem. I've done some pretty neat work with this (smooth pan and zoom of 6000x4000 image) - it is definitely memory effective if used right.

[EDIT]

I recently open-source my own dumb implementation using BitmapRegionDecoder which handles pan, fling, and pinch-zoom of a very large bitmap. You can find the code (ASL2.0) at https://github.com/micabyte/android_game

The class you want to look at is BitmapSurfaceRenderer. So far I've tested it with up to 8000x4000 images, and it seems to work very well. When I get the time, I'll put up a simple example app that demonstrates how it is used as well.

 

answered Sep 13, 2013 by rajesh
edited Sep 12, 2013
0 votes
Use the method Bitmap.recycle() before nullfying Bitmap object. Below is the sample: public final void setBitmap(Bitmap bitmap) { if (this.myBitmapImage != null) { this.myBitmapImage.recycle(); } this.myBitmapImage = bitmap; } And next you can change myBitmapImage without calling System.gc() as follows: setMyBitmap(anotherBitmap); setMyBitmap(null);
answered Sep 13, 2013 by rajesh
edited Sep 12, 2013
0 votes
Try to get rid of outstream before you decode nulling the pointer (closing this specific stream will do nothing). You're doing quite an extensive operation here so we need to be as light as possible...

Your code also lacks closing the input stream (which is not the bug here, but still should be done after you decodeStream).

Try and look into Nostras ImageLoader as it efficiently handles loading images into specific sized containers, i.e resizing and compressing them, before you will need to handle them. It also supports content uris which will help you all at once.
answered Sep 13, 2013 by rajesh
edited Sep 12, 2013
0 votes
Use the method Bitmap.recycle() before nullfying Bitmap object. Below is the sample: public final void setBitmap(Bitmap bitmap) { if (this.myBitmapImage != null) { this.myBitmapImage.recycle(); } this.myBitmapImage = bitmap; } And next you can change myBitmapImage without calling System.gc() as follows: setMyBitmap(anotherBitmap); setMyBitmap(null);
answered Sep 13, 2013 by rajesh
edited Sep 12, 2013
0 votes

Ah - the many wonderful battles one may have with Google's implementation of bitmap handling in Android.

I would tend to do some memory profiling anytime I hit the roof with memory - very often (although not always) it is because one is doing something wrong (i.e., unexpectedly memory intensive). Just browsing the code, I am a little bit puzzled by the need to force the code through three streams, just to end up with a bitmap again. I feel as if I'm missing some information for me to make sense of this, but I'd definitely take a look at just how much memory you're allocating in each of those steps if I were you (heap dump -> hprof-conv -> memory analyzer is your friend).

However, I suspect that what you may be looking for is BitmapRegionDecoder. I actually only recently discovered this myself, but I think it does pretty much exactly what you are after - allows you to decode a region from a bitmap (inputstream) without loading the entire bitmap into memory (you can also get the width/height). Only downside is that it is Android 2.3.3+ only, but these days that >90% of the market so that should not be a huge problem. I've done some pretty neat work with this (smooth pan and zoom of 6000x4000 image) - it is definitely memory effective if used right.

[EDIT]

I recently open-source my own dumb implementation using BitmapRegionDecoder which handles pan, fling, and pinch-zoom of a very large bitmap. You can find the code (ASL2.0) at https://github.com/micabyte/android_game

The class you want to look at is BitmapSurfaceRenderer. So far I've tested it with up to 8000x4000 images, and it seems to work very well. When I get the time, I'll put up a simple example app that demonstrates how it is used as well.

 

answered Sep 13, 2013 by rajesh
edited Sep 12, 2013
0 votes
Try to get rid of outstream before you decode nulling the pointer (closing this specific stream will do nothing). You're doing quite an extensive operation here so we need to be as light as possible...

Your code also lacks closing the input stream (which is not the bug here, but still should be done after you decodeStream).

Try and look into Nostras ImageLoader as it efficiently handles loading images into specific sized containers, i.e resizing and compressing them, before you will need to handle them. It also supports content uris which will help you all at once.
answered Sep 13, 2013 by rajesh
edited Sep 12, 2013

...