Heap not expanding on Genymotion emulator - android

While resizing large bitmaps for faster image upload to a server I occasionally ran into OutOfMemoryErrors.
To prevent this I calculate the required amount of memory and check if it exceeds Runtime.getRuntime().maxMemory() before trying to scale an image.
However, I still run into OOM errors even though the image should fit on the heap easily.
The emulated device (Galaxy SII API 16) gives me a max memory of 67108864 bytes using the above method.
In the following snippet, the heap size is 43975K and only < 15K of that memory is in use. For my ~31K allocation the heap should grow automatically to about 45K which is still not even close to the maximum size of 64 MiB.
But as you can see, instead of expanding the heap, the dalvik vm runs out of memory.
10-13 20:35:57.223: D/dalvikvm(1201): GC_FOR_ALLOC freed 505K, 67% free 14692K/43975K, paused 31ms, total 31ms
10-13 20:35:57.223: I/dalvikvm-heap(1201): Forcing collection of SoftReferences for 31961100-byte allocation
10-13 20:35:57.251: D/dalvikvm(1201): GC_BEFORE_OOM freed 2K, 67% free 14689K/43975K, paused 29ms, total 29ms
10-13 20:35:57.251: E/dalvikvm-heap(1201): Out of memory on a 31961100-byte allocation.
I wonder if this can happen on a real device too or if this could be a genymotion bug.
Is the heap guaranteed to expand up to maxMemory()? The JavaDoc for Runtime.getRuntime().freeMemory() says it "may" expand, whatever that means.
I just need a realiable way to calculate the amount of memory I can use, this is how I did it, please correct me if I'm wrong:
long maxMemory = Runtime.getRuntime().maxMemory();
long usedMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
long availableMemory = maxMemory - usedMemory;
This call causes the OutOfMemoryError:
// outOptions has an appropriate inSampleSize
BitmapFactory.decodeStream(inputStream, null, outOptions);

Out of memory on a 31961100-byte allocation
Your bitmap is 32M. VM can't allocate 32M linear space to store bitmap. Heap is fragmented, so even if your heap has 32M free space it is not always possible to allocate such linear space. You can try free up as much memory as you can and call GC before decoding stream.
Try to decode your bitmap in more effective way. Or process image in parts.
If you tell us why you need this image, we can tell you how to handle it.

You have a 42MB heap , out of which 14MB is already used, 67% (28M) is free/available
D/dalvikvm(1201): GC_BEFORE_OOM freed 2K, 67% free 14689K/43975K, paused ...
E/dalvikvm-heap(1201): Out of memory on a 31961100-byte allocation.
You are trying to allocate ~31M (not 31K) , which is greater than 28M that is available, resulting in OOM.
For details on interpreting dalvikvm memory allocation log message take a look at debugging memory
There is lot of shared memory usage going on in android, to properly calculate per process memory usage refer this SO question
Android best practices on efficient bitmap memory management may be of help

One thing you might try to tweak is build.props file of the ROM.
On Genymotion emulator you can try executing the following via root shell:
cat /system/build.prop | grep dalvik
and it would display the line with dalvik settings:
dalvik.vm.heapsize=256m
dalvik.vm.lockprof.threshold=500
dalvik.vm.stack-trace-file=/data/anr/traces.txt
And maxmemory is also being reported as 268435456 bytes on the emulator I experimented with.
So, you may try playing with this setting. Also, ensure that the memory allocated in VirtualBox's settings is compatible with these values.

Related

Bitmap OutOfMemoryError even using recycle()

I have an app that shows a lot of activities, each one showing a bitmap that fits the 100% of the width of the screen and normally more than the 100% of the height.
When you touch the screen, a new activity is created, and in the previous activity is being called finish and recycle for the bitmap:
public void clean() {
if(this.myBitmap != null){
Log.d(DEBUG_TAG, " Cleaning "+this);
this.myBitmap.recycle();
this.myBitmap=null;
System.gc();
}
}
the problem is that the memory required is growing and growing and when i am launching more than 12-13 activities these messages are being showed at logcat:
05-05 16:03:02.909: I/dalvikvm-heap(24794): Clamp target GC heap from 65.790MB to 64.000MB
05-05 16:03:02.969: D/dalvikvm(24794): GC_EXPLICIT freed 71K, 5% free 59008K/61680K, paused 2ms+13ms, total 55ms
05-05 16:03:03.559: I/dalvikvm-heap(24794): Clamp target GC heap from 67.197MB to 64.000MB
05-05 16:03:03.569: D/dalvikvm(24794): GC_EXPLICIT freed 418K, 2% free 60521K/61680K, paused 3ms+28ms, total 109ms
after a few activities more i got this crash:
05-05 16:03:05.049: E/AndroidRuntime(24794): java.lang.OutOfMemoryError
05-05 16:03:05.049: E/AndroidRuntime(24794): at android.graphics.Bitmap.nativeCreate(Native Method)
05-05 16:03:05.049: E/AndroidRuntime(24794): at android.graphics.Bitmap.createBitmap(Bitmap.java:809)
05-05 16:03:05.049: E/AndroidRuntime(24794): at android.graphics.Bitmap.createBitmap(Bitmap.java:786)
05-05 16:03:05.049: E/AndroidRuntime(24794): at android.graphics.Bitmap.createBitmap(Bitmap.java:718)
I dont know what is going wrong here, i am doing recycle() of the bitmap and also i tryed with and without System.gc(), in both cases i got the crash
Its a known bug, its not because of large files. Since Android Caches the Drawables, its going out of memory after using few images. But i found alternate way for it, by skipping the android default cache system.
Soultion:
Create a drawable folder in Assets and move the images to "drawable" folder in assets and use the following function to get BitmapDrawable
public static Drawable getAssetImage(Context context, String filename) throws IOException {
AssetManager assets = context.getResources().getAssets();
InputStream buffer = new BufferedInputStream((assets.open("drawable/" + filename + ".png")));
Bitmap bitmap = BitmapFactory.decodeStream(buffer);
return new BitmapDrawable(context.getResources(), bitmap);
}
Refrence : https://stackoverflow.com/posts/6116316/revisions
Also that add the line below in your manifest file
android:largeHeap="true"
Use DDMS to grab a heap dump and do some analysis on the dump using Eclipse Memory Analyzer (built into Eclipse ADT or can run stand-alone). What your looking for is objects that you allocated but are not being freed. One possibility is that you are leaking activities. You say the OOM error occurs after launching 12-13 activities. Only one of the activities should be visible at a time so you can free memory from the paused activities in the onPause() or onStop() method. Again, analyzing the heap dump will give you a good idea of what is eating up the heap memory.
FYI - Bitmap#recycle() is only really necessary on Gingerbread and lower devices. On newer version of the OS bitmaps are stored on the heap and are garbage collected like other objects. See, the "Manage Memory on Android 2.3.3 and Lower" section of this document: https://developer.android.com/training/displaying-bitmaps/manage-memory.html

Grow Heap problems in Android

I got problems about grow heap which I have 2 questions to ask.
First, How can I suppose to check current grow heap in my devices?
Second, How can I decrease my grow heap size to prevent out of memory error?
Do you mean you want to check the total size of the heap your application can use? Or how much free memory is left in the heap?
To see the total size of the heap you could call
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));
This will tell you how much memory in bytes your app is allowed to use (source)
To find out how much is left you could do the following
When are you getting out of memory errors? A starting point could be to override onLowMemory() method...

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.

Android Heap Memory size doesn't looks correct

i have an Android app that displays alot of images, it works, the images are gatherd from an url, added to a que and gathered by 4 threads,stored in a cache and then displayed in a listview view 4 images for row, there are abot six rows at each time on the screen. There is a total of usually 90 images.
The rows(and imageviews) are always recycled, so the amount of items is always the same and i'm not initializing anything.
This seems to work quite fine, i have always an average used heap size of 13MB.
The problem i have is that at the beginning mi max heap size is quite small and i get GC messages like:
01-20 16:48:39.191: D/dalvikvm(9743): GC_FOR_ALLOC freed <1K, 31% free 12048K/17351K, paused 25ms
but the more i scroll up down the view the heap size grows more and more untile i get things like
01-20 17:02:05.339: D/dalvikvm(11730): GC_FOR_ALLOC freed 544K, 72% free 13871K/49159K, paused 35ms
as you see even if the used is the same the maximum is increased even if i never got to that limit. and the true problem is that at this point i start to get outofmemory errors.
Can someone explain me what's wrong?
Thanks!
What version of Android are you using? If you're testing on pre 3.0 (ie 2.x), the byte arrays that store most of the information in Bitmaps are allocated and stored in native memory. This means that in heap dumps and in the GC notifications, you only see the small amount of memory used for pointers in Bitmaps, rather than the actual size.
For more information check out this google IO talk on memory management and detecting memory leaks: http://www.youtube.com/watch?v=_CruQY55HOk
Also I've worked on several apps doing similar things. My guess is that either your cache size is way too large, or (more likely) the images you're displaying and storing in the cache are much larger than the size you actually want. If you display a bitmap in an image view, the imageview will store the original bitmap in memory, even if it is significantly larger than what would actually fit in the view. Try resizing the images from disk to at least closer to the appropriate size before trying to display them: How do I scale a streaming bitmap in-place without reading the whole image first?
To cache my Images I use Map<String, Drawable> drawableMap. On a OutOfMemoryError I call this function:
private void cacheLeeren()
{
int size = drawableMap.size();
int del = (int) (size * 0.3);
Set<String> s = drawableMap.keySet();
for (String t : s)
{
if (del >= 0)
{
drawableMap.put(t, null);
del--;
}
}
}
I think it's not the best way...but it works ;-)
My guess is that your app reaches a very high peak of memory usage for a short time. It's true that on average you only use 13MB but if your heap grows to as much as 50MB, it means that momentarily you've consumed much more memory than you're thinking.
Let's try to figure out where this is happening. You've mentioned that you're using an LRU cache. This cache frees memory as soon as it fills up. My guess is that you're starting to free memory too late, and this memory isn't freed immediately - since it depends on the system GC. Whenever you're freeing some items from the cache, try to call System.gc() manually.
You've also mentioned that you're calling Bitmap.recycle(). To the best of my knowledge this is useless on Android 3+ because the native heap is no longer used for bitmaps. Since all bitmaps are on the dalvik heap, they will be freed by the GC.. You can't rush this like before unless you call System.GC() yourself.
Another idea for your source of problems is heap fragmentation. See my previous SO answer to a similar issue in this question.

Categories

Resources