Manoj
Manoj

Reputation: 2829

Grow Heap size and OutOfMemory error

I have one image about 1948X674 dimension and 104kb in size. It gives OutOfMemoryError on Samsung galaxy S3. I am showing this image in horizontal scrollview. Here is my xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Panorama" >

    <HorizontalScrollView
        android:id="@+id/hscroll"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_above="@+id/tapToEnter"
        android:scrollbars="none" >

        <ImageView
            android:id="@+id/imgPanorama"
            android:layout_width="wrap_content"
            android:layout_height="match_parent" />
    </HorizontalScrollView>

    <Button
        android:id="@+id/tapToEnter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="Tap to enter" />

</RelativeLayout>

and i am setting image to it programatically. decodeSampledBitmapFromResource() i am using from Loading Large Bitmap Efficiently .

Bitmap bmp;
try
        {
        BitmapDrawable bd=(BitmapDrawable)getResources().getDrawable(R.drawable.panorama);
        reqwidth=bd.getIntrinsicWidth();
        reqheight = bd.getIntrinsicHeight();
        }catch(OutOfMemoryError oom)
        {
            oom.printStackTrace();
        }
bmp=decodeSampledBitmapFromResource(getResources(),R.drawable.panorama, reqwidth, reqheight);
imgPanorama.setImageBitmap(bmp);




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;
    }
    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
            int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inPurgeable=true;
        /*options.inDither=false;                     //Disable Dithering mode
        options.inPurgeable=true;                   //Tell to gc that whether it needs free memory, the Bitmap can be cleared
        options.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
        options.inTempStorage=new byte[32 * 1024];
        */
        BitmapFactory.decodeResource(res, resId, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }


@Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        if(bmp!=null  && !bmp.isRecycled())
        {
            bmp.recycle();
            bmp=null;

        }
    }

Here is my logcat when i start activity.

03-20 11:20:36.175: I/dalvikvm-heap(30452): Grow heap (frag case) to 17.982MB for 5251824-byte allocation
03-20 11:20:36.260: I/dalvikvm-heap(30452): Grow heap (frag case) to 38.014MB for 21007248-byte allocation
03-20 11:20:36.385: I/dalvikvm-heap(30452): Grow heap (frag case) to 38.016MB for 5251824-byte allocation
03-20 11:20:36.480: I/dalvikvm-heap(30452): Grow heap (frag case) to 58.050MB for 21007248-byte allocation

Upvotes: 2

Views: 2151

Answers (1)

David Manpearl
David Manpearl

Reputation: 12656

Bitmap.recycle() is your friend because it allows the image's pixel data to be freed much more quickly than manual or automatic garbage collection will do the same job. Therefore, when you are finished with a large image, it can be a good idea to recycle() it before allowing it to go out of scope. Of course it will be automatically garbage collected after it goes out of scope, but recycle() will immediately release the vast majority of the memory used by the Bitmap.

For example, you may choose to recycle() after copying a Bitmap to a UI element:

Bitmap bmp;
bmp=decodeSampledBitmapFromResource(getResources(),R.drawable.panorama, reqwidth, reqheight);
imgPanorama.setImageBitmap(bmp);

// Free the pixel data immediately in order to keep heap from growing out of control.
// This is especially useful while displaying multiple images.
bmp.recycle();

You may also experiment with smaller values of reqwidth and reqheight, which will allow larger calculated inSampleSize so that your Bitmap will use significantly less memory.

Upvotes: 2

Related Questions