Android: Out of Memory Exception in Gallery

Android: out of memory exception in Gallery


The images are fetched from the Web,
each ranging from 300K to 500K in
size, and stored in an arrayList of
Drawables.

The kb file size of the image you're loading from the web isn't directly relevant. Since they're converted into bitmaps you need to calculate width * height * 4 bytes per image for regular ARGB images. (width and height in px).

The bitmaps consume native heap, which usually doesn't show in a hprof. The hprof should only show you the number of objects, i.e. BitmapDrawables or Bitmaps that are left.

I use this code in my app to output the current used memory used by the app and native heap:

public static void logHeap(Class clazz) {
Double allocated = new Double(Debug.getNativeHeapAllocatedSize())/new Double((1048576));
Double available = new Double(Debug.getNativeHeapSize())/1048576.0);
Double free = new Double(Debug.getNativeHeapFreeSize())/1048576.0);
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setMinimumFractionDigits(2);

Log.d(APP, "debug. =================================");
Log.d(APP, "debug.heap native: allocated " + df.format(allocated) + "MB of " + df.format(available) + "MB (" + df.format(free) + "MB free) in [" + clazz.getName().replaceAll("com.myapp.android.","") + "]");
Log.d(APP, "debug.memory: allocated: " + df.format(new Double(Runtime.getRuntime().totalMemory()/1048576)) + "MB of " + df.format(new Double(Runtime.getRuntime().maxMemory()/1048576))+ "MB (" + df.format(new Double(Runtime.getRuntime().freeMemory()/1048576)) +"MB free)");
System.gc();
System.gc();

// don't need to add the following lines, it's just an app specific handling in my app
if (allocated>=(new Double(Runtime.getRuntime().maxMemory())/new Double((1048576))-MEMORY_BUFFER_LIMIT_FOR_RESTART)) {
android.os.Process.killProcess(android.os.Process.myPid());
}
}

which I call when starting or finishing an activity during development.

logHeap(this.getClass());

Here are some informative links - generally there are lots of threads about this topic on here.

  • Bitmaps in Android
  • Android: Eclipse MAT does not appear to show all my app's objects

Here's also a useful slide by Romain Guy (Android Framework engineer) about soft references, weak references, simple caches, image handling:
http://docs.huihoo.com/google/io/2009/Th_0230_TurboChargeYourUI-HowtomakeyourAndroidUIfastandefficient.pdf

android how to avoid this out of memory error

if image view hold an instance of bitmap drawable

Drawable drawable = imageView.getDrawable();
if(drawable!=null && BitmapDrawable.class.isAssignableFrom(drawable.getClass())) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
Bitmap bitmap = bitmapDrawable.getBitmap();
if(bitmap != null && !bitmap.isRecycled()) bitmap.recycle();
}

but...

If you are loading bitmaps from drawable folders that are not large (large as in megabytes) then you should not really run into a problem.

If you loading assets you need to check if they are optimal for where you display them, for example there is no point in setting an ImageView to an image thats 1024 x 1024 in size if the area you display the image is a size of 64x64.

OOM often is caused by loading images of an unknown size or just simply getting the image sizes wrong as described above, swapping an ImageView frequently will generally not give you an issue with optimal sized images.

You should read some guidance on bitmaps:

https://developer.android.com/training/displaying-bitmaps/index.html

for your case:

this is essential fragment from stack trace :

FATAL EXCEPTION: main Process: ss.sealstudios.com.socialstories, PID: 13189 
java.lang.OutOfMemoryError: Failed to allocate a 2073612 byte allocation with 559872 free bytes and 546KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:1080)
at android.content.res.Resources.loadDrawableForCookie(Resources.java:2738)
at android.content.res.Resources.loadDrawable(Resources.java:2643)
at android.content.res.Resources.getDrawable(Resources.java:833) at android.content.res.Resources.getDrawable(Resources.java:786)
at ss.sealstudios.com.socialstories.TwoFragment.prepareCardData(TwoFragment.java:280)

Failed to allocate a 2073612 byte allocation with 559872 free bytes and 546KB until OOM

so generally:

  • in method TwoFragment.prepareCardData(TwoFragment.java:280)
    befor call to Resources.getDrawable(..) you should get image view and recycle bitmap..
  • in fragment/activity you should also recycle bitmap in onDestroy() method

without more code i'm not able to determine if for example some loop is causing OOM or you are not releasing resources...

you can also do this (scale image) before settings up resource to image view:

Out of Memory Error ImageView issue

caution!!!

Do not use image you already recycled.

You'll get exception: Canvas: trying to use a recycled bitmap

bitmap.recycle() is not strictly required for android >2.3.3. If you still want to reclaim this memory forcefully, you'll have to find a way to check when the bitmap is indeed no longer needed (i.e., Canvas had a chance to finish its drawing operations).

the problem is that you probably making extensive use of Bitmaps (speed of allocation may be greater than speed at which bitmap getting recycled) then you might want to recycle unused bitmaps ASAP.You should call recycle() when you are done using the bitmap.

Always remember don't try to recycle bitmap when it is being shown on the screen.

So:

  • grab reference to old bitmap
  • set new one
  • invalidate view
  • check if old bitmap is not already recycled
  • recycle old one
  • you can also call System.gc(); ^

^Indicates to the VM that it would be a good time to run the garbage collector. Note that this is a hint only. There is no guarantee that the garbage collector will actually be run.

call to ImageView.setImageBitmap(); or similarity will not reclaim memory used by bitmap...

Why? because when u look at the impl of ImageView method especially:

private void updateDrawable(Drawable d) {
if (d != mRecycleableBitmapDrawable && mRecycleableBitmapDrawable != null) {
mRecycleableBitmapDrawable.setBitmap(null);
}
...


public void setImageResource(@DrawableRes int resId) {
// The resource configuration may have changed, so we should always
// try to load the resource even if the resId hasn't changed.
final int oldWidth = mDrawableWidth;
final int oldHeight = mDrawableHeight;

updateDrawable(null);
....

public void setImageBitmap(Bitmap bm) {
// Hacky fix to force setImageDrawable to do a full setImageDrawable
// instead of doing an object reference comparison
mDrawable = null;
if (mRecycleableBitmapDrawable == null) {
mRecycleableBitmapDrawable = new ImageViewBitmapDrawable(
mContext.getResources(), bm);
} else {
mRecycleableBitmapDrawable.setBitmap(bm);
}
setImageDrawable(mRecycleableBitmapDrawable);
}

See also:

https://developer.android.com/training/displaying-bitmaps/manage-memory.html

Out of memory exception while implementing image gallery

use convertView is not null then try to else

     @Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder2;
if (convertView == null) {

holder2 = new ViewHolder();
convertView = mInflater.inflate(
R.layout.one_image, null);
holder1 = (ImageView)convertView.findViewById(R.id.PhotoImage);
convertView.setTag(holder1);

}
else {

holder2= (ViewHolder) convertView .getTag();
}

return convertView;
}

private static class ViewHolder {
ImageView holder1;

}

android Image view out of memory error

in your code start at if(null != path) change to this

int size = 10; //minimize  as much as you want
if(path != null){
Bitmap bitmapOriginal = BitmapFactory.decodeFile(pathath);
Bitmap bitmapsimplesize = Bitmap.createScaledBitmap(bitmapOriginal,bitmapOriginal.getWidth() / size, bitmapOriginal.getHeight() / size, true);
bitmapOriginal.recycle();
img1.setImageBitmap(bitmapsimplesize);

}


Related Topics



Leave a reply



Submit