Android - Out of memory while loading bitmaps - android

I have 3 activities, while I switch from 2 to 3, my app like restarts and jumps to 1.
I drag bitmap from activity to another one.
What to do? What trick shoul i use less memory?
02-02 06:29:20.017 1509-1509/marty.martzero D/dalvikvm﹕ GC_FOR_ALLOC freed 508K, 6% free 21312K/22663K, paused 29ms, total 29ms
02-02 06:29:20.027 1509-1509/marty.martzero E/io﹕ bitmaptosave = xz
02-02 06:29:20.586 1526-1526/marty.martzero D/dalvikvm﹕ GC_FOR_ALLOC freed 69K, 4% free 8003K/8259K, paused 28ms, total 29ms
02-02 06:29:20.606 1526-1526/marty.martzero I/dalvikvm-heap﹕ Grow heap (frag case) to 10.228MB for 2479056-byte allocation
02-02 06:29:20.656 1526-1528/marty.martzero D/dalvikvm﹕ GC_CONCURRENT freed <1K, 3% free 10424K/10695K, paused 15ms+10ms, total 54ms
02-02 06:29:20.857 1526-1528/marty.martzero D/dalvikvm﹕ GC_CONCURRENT freed 1K, 2% free 11189K/11335K, paused 16ms+3ms, total 56ms
02-02 06:29:20.937 1526-1526/marty.martzero D/libEGL﹕ loaded /system/lib/egl/libEGL_emulation.so
02-02 06:29:20.947 1526-1526/marty.martzero D/﹕ HostConnection::get() New Host Connection established 0x2a0fcf60, tid 1526

First of all, know that Bitmaps are evil in mobile applications. They occupy big chunk of RAM if they are not used efficiently. Following methods might help for a better memory management:
Use a singleton to hold on to your bitmaps.
However, be very careful about memory leak in android, see this.
DO NOT recreate a bitmap which has already been loaded to the memory. For example do not recreate a scaled version of Bitmap while you still hold a reference to the original version of a bitmap. If you need different sizes of a single bitmap, use matrix manipulation, rather than resizing the Bitmap itself each time.
Do this:
canvas.drawBitmap(bitmap, srcRect, dstRec1, null);
canvas.drawBitmap(bitmap, srcRect, dstRec2, null);
canvas.drawBitmap(bitmap, srcRect, dstRec3, null);
And NOT this:
canvas.drawBitmap( bitmap1, left1, top1, null);
canvas.drawBitmap( bitmap2, left2, top2, null);
canvas.drawBitmap( bitmap3, left3, top3, null);
where bitmap1, bitmap2, and bitmap3 are the same file only with different scaling.
Try to load bitmap as small size as you can. Read more details about sampling here.
Finally, if your application really really needs a big heap size, you can request a bigger heap through setting up a flag in your manifest, application section:
android:largeHeap="true"

You can make your bitmap public and static, and use it in another activity. There is no need to drag with activity.
And another way to compress bitmap to reduce memory size
BitmapFactory.Option imageOpts = new BitmapFactory.Options ();
imageOpts.inSampleSize = 2; // for 1/2 the image to be loaded
Bitmap thumb = Bitmap.createScaledBitmap (BitmapFactory.decodeFile(photoPath, imageOpts), 96, 96, false);

Related

How to avoid out of memory when I start a second animation drawable

I am a newbie in Android and now I am totally lost... could you give me some hints with my code?
I am trying to run a stop motion animation using AnimationDrawable from some of the images that I previously copied to the res folder of the project. The images to be used in the animation are selected in runtime, so I used addFrame to include them. When user push a button the animation starts successfully with the selected images. Then the user is asked for select new images and again, after pushing the button, the new animation should start. The problem is that then it causes OUT OF MEMORY errors. These errors do not happens in the first animation, so it seems that I am wasting the memory of the phone (or emulator) with the successive animations. How could I release the memory used in the first animation before starting the second one?
I tried using ((BitmapDrawable)frame).getBitmap().recycle(); but then I can not use the image for the second animation.
Any suggestions?
This is the relevant part of my code, I guess:
int globeId = this.getResources().getIdentifier(resname1, "drawable",
this.getPackageName());
animation.addFrame(this.getResources().getDrawable(globeId), velocidad);
int globeId = this.getResources().getIdentifier(resname2, "drawable",
this.getPackageName());
animation.addFrame(this.getResources().getDrawable(globeId), velocidad);
...
animation.setOneShot(true);
imageAnim.setBackgroundDrawable(animation);
animation.start();
And this is the error:
D/dalvikvm: GC_FOR_ALLOC freed 1251K, 5% free 59812K/62471K, paused 4ms, total 4ms
D/dalvikvm: GC_FOR_ALLOC freed <1K, 3% free 61062K/62471K, paused 4ms, total 4ms
I/dalvikvm-heap: Forcing collection of SoftReferences for 5119532-byte allocation
D/dalvikvm: GC_BEFORE_OOM freed 9K, 3% free 61052K/62471K, paused 4ms, total 6ms
E/dalvikvm-heap: Out of memory on a 5119532-byte allocation.

Why is Android allocating twice as much memory as I expect for an image?

I'm loading an image resource in an Android application using setImageResource(), and for some reason this is using a lot of extra memory.
This is what I see when the image is loaded:
03-29 15:16:56.687: D/dalvikvm(23616): GC_FOR_ALLOC freed 42K, 11% free 16175K/18119K, paused 11ms
I/dalvikvm-heap(23616): Grow heap (frag case) to 23.154MB for 7675216-byte allocation
D/dalvikvm(23616): GC_CONCURRENT freed 3K, 8% free 23667K/25671K, paused 1ms+2ms
D/dalvikvm(23616): GC_FOR_ALLOC freed 0K, 8% free 23667K/25671K, paused 10ms
I/dalvikvm-heap(23616): Grow heap (frag case) to 39.624MB for 17272816-byte allocation
D/dalvikvm(23616): GC_CONCURRENT freed 0K, 5% free 40535K/42567K, paused 1ms+2ms
The jpg is 1599x1200, so I would expect the first allocation - 1599 * 1200 * 4 = 7675200.
What's going on with the 17MB allocation?
It is most likely you put your image into drawable-mdpi or just drawable directory, but run the app on the hdpi device. In this case image's dimensions will be scaled by 1.5.
1599 * 1200 * 4 * 1.5 * 1.5 = 17269200b ~ 17mb
You should probably move the image to drawable-nodpi directory to avoid unwanted scale.

Android - Grow Heap (Frag Case) - Byte Allocation.. Not Loading any bitmaps

This happens when the app loads from Splash screen to Main page. It happens only on the device not on simulator:
05-17 08:10:16.627: I/dalvikvm-heap(14021): Grow heap (frag case) to 20.580MB for 2424256-byte allocation
05-17 08:10:16.666: D/dalvikvm(14021): GC_FOR_ALLOC freed 1K, 3% free 21000K/21511K, paused 21ms
05-17 08:10:16.697: D/dalvikvm(14021): GC_CONCURRENT freed 116K, 3% free 20885K/21511K, paused 2ms+2ms
05-17 08:10:16.720: D/dalvikvm(14021): GC_FOR_ALLOC freed 44K, 4% free 20841K/21511K, paused 10ms
05-17 08:10:16.728: I/dalvikvm-heap(14021): Grow heap (frag case) to 24.533MB for 4310896-byte allocation
I used Ecplise MAT - the byte allocation resolved - Android.Graphics.Bitmap $preloaded images...
The device I am using is Google Nexus Prime, Android 4.0
Has anyone encountered the same? Can someone throw some expertise....
I have experienced the same issue and found a solution to it.
Are you loading your bitmaps from resource? if so try placing them in corresponding drawable folders instead of keeping them in "drawable" or "drawable-mdpi".
When you have your image resources in plain drawable folder, to the system it means drawable-mdpi. Therefore devices with high or extra high dpi (Galaxy Nexus I believe is Extra high) will expand that resource to match the dpi of the device.
If you only have 1 size for your resources, put them in drawable-nodpi and it will be used as is. However some of your layouts may be affected by this, so I kept certain images in the drawable folder (like button images etc.) and moved backgrounds and other bigger resources into drawable-nodpi.
Hope this helps ;)
You are probably trying to decode a very big Bitmap which results in an OutOfMemory exception. It means that the operation you are trying to achieve is exceeding the VM Budget allowed for each application on your device, in terms of heap memory consumption (which appears to be 24 MB on your device, probably more on your emulator which is why it doesn't happen there!).
Try to sample your Bitmapby a factor of two for instance:
BitmapFactory.Options o = new BitmapFactory.Options();
o.inSampleSize = 2;
Bitmap b = BitmapFactory.decodeFile(pathToBitmap, o);

Android Bitmap Memory Use

I am running a stack of image filters and seem to be hitting some memory issues.
At the beginning of the image processing I am using this much memory:
GC_FOR_MALLOC freed 3K, 45% free 3237K/5831K, external 47586K/49634K, paused 17ms
At the end I am using this much (after all processing is finished):
GC_EXTERNAL_ALLOC freed 5K, 16% free 16056K/18951K, external 51430K/52196K, paused 23ms
After I am finished with each bitmap I set it to recycle and to null:
someBitmap.recycle();
someBitmap = null;
Is there anything else I should be doing to them? Is there any cleanup I should do to the Canvas being used?
Also my filters are objects instantiated like:
BoxBlurFilter blurFilter = new BoxBlurFilter();
Is there anything I should do to release them? In iOS memory allocated with "new" I am responsible to free.
Sorry for the trivial memory management questions, but I am quite new to Android dev and things are quite different than iOS.
Thank you!
EDIT 2, I removed my full filter code.
So after setting the filter instances to null and all the byte arrays to null (in the code above and in the filter objects) I now have approximately the same size heap as I did before I run the filter:
GC_EXPLICIT freed 5126K, 77% free 3243K/13703K, external 51430K/53478K, paused 18ms
That means it went from 16mb being used to 3.2mb. Much better!
So I guess the answer to my question is make sure you set everything to null if you want it to be freed.

OutOfMemory error though free memory is available

I'm seeing a pretty odd problem. Essentially sometimes large bitmap memory allocations will fail even though there's apparently tons of memory. There are a number of posts that appear to ask a similar question but they are all related to pre-honeycomb android. My understanding is that images are allocated on heap now, instead of some outside memory. Anyway, please look at this log below:
10-14 13:43:53.020: INFO/dalvikvm-heap(31533): Grow heap (frag case) to 40.637MB for 942134-byte allocation
10-14 13:43:53.070: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 126K, 11% free 41399K/46343K, paused 31ms
10-14 13:43:53.130: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 920K, 13% free 40478K/46343K, paused 30ms
10-14 13:43:53.180: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 1026K, 13% free 40479K/46343K, paused 30ms
10-14 13:43:53.250: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 931K, 12% free 41193K/46343K, paused 31ms
10-14 13:43:53.250: INFO/dalvikvm-heap(31533): Grow heap (frag case) to 41.313MB for 1048592-byte allocation
10-14 13:43:53.280: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed <1K, 11% free 42217K/47431K, paused 31ms
10-14 13:44:01.520: DEBUG/dalvikvm(31533): GC_CONCURRENT freed 3493K, 15% free 40646K/47431K, paused 3ms+9ms
10-14 13:44:08.130: DEBUG/dalvikvm(31533): GC_EXPLICIT freed 16461K, 47% free 25527K/47431K, paused 3ms+6ms
10-14 13:44:09.150: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 1007K, 45% free 26191K/47431K, paused 35ms
10-14 13:44:09.160: INFO/dalvikvm-heap(31533): Grow heap (frag case) to 29.334MB for 3850256-byte allocation
10-14 13:44:09.200: DEBUG/dalvikvm(31533): GC_CONCURRENT freed 0K, 37% free 29951K/47431K, paused 2ms+4ms
10-14 13:44:11.970: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 1878K, 38% free 29784K/47431K, paused 37ms
10-14 13:44:12.410: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed 62K, 36% free 30441K/47431K, paused 32ms
10-14 13:44:12.440: DEBUG/dalvikvm(31533): GC_FOR_ALLOC freed <1K, 32% free 32325K/47431K, paused 32ms
10-14 13:44:12.440: INFO/dalvikvm-heap(31533): Forcing collection of SoftReferences for 3850256-byte allocation
10-14 13:44:12.480: DEBUG/dalvikvm(31533): GC_BEFORE_OOM freed 124K, 33% free 32200K/47431K, paused 37ms
10-14 13:44:12.480: ERROR/dalvikvm-heap(31533): Out of memory on a 3850256-byte allocation.
I apologise for including so much logging, I hope it's relevant. The way I read it is that the system continuously readjusts heap size until it eventually reaches heap max. Then, we request an especially large allocation that fails. Clearly there is more than enough memory available (about 15 megs). Does this mean that heap is internally fragmented and there are no contiguous memory segments large enough to handle our allocation? If that's the case what should I do? If that's not it, then what?
Thanks in advance.
The weird behavior is because bitmaps are allocated on the native heap and not on the garbage collected, but android can only track objects on the garbage collected heap. From Android 2.2 (or 2.3 maybe) this has changed and allocated bitmaps are visible too if you make a heap dump.
Back to the question, your problem is most probably that the bitmaps you loaded manually are not freed appropriately. One typical problem is that some callback remains set or the view is still referring the bitmap.
The other common problem is that if you load big bitmaps manually (not as a resource), you will need to call recycle() on them when you don't need it anymore, which will free the bitmap from the native memory so the garbage collector will be able to its work as it should. (The GC only sees objects on the GC heap, and doesn't no which object to free to free memory from the native heap, and actually doesn't even care about it.)
I have this little baby at hand all the time:
public static void stripImageView(ImageView view) {
if ( view.getDrawable() instanceof BitmapDrawable ) {
((BitmapDrawable)view.getDrawable()).getBitmap().recycle();
}
view.getDrawable().setCallback(null);
view.setImageDrawable(null);
view.getResources().flushLayoutCache();
view.destroyDrawingCache();
}
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
The system doesn't readjust heap sizes. Your app has a (semi-) predefined heap space. Heap sizes can be adjusted in some custom ROMs. This isn't really germane to your problem though.
The order of the garbage collection you're seeing seems to suggest that at the time of the GC_BEFORE_OOM happens your app's running out of its heap space. The stats reported by the Dalvik logger could be system-wide.
yes the error "out of Memory" occur when we are working with big size Bitmap. for that i have an solution, with Decoding of the image we can easily avoid this error.
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream fis = new FileInputStream(files.getAbsolutePath());
BitmapFactory.decodeStream(fis, null, o);
fis.close();
final int REQUIRED_SIZE=70;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
BitmapFactory.Options op = new BitmapFactory.Options();
op.inSampleSize = scale;
fis = new FileInputStream(files.getAbsolutePath());
bitmap[i] = BitmapFactory.decodeStream(fis, null, op);
fis.close();

Categories

Resources