I know this subject has been discussed a lot, but I can't find workaround/solution for my memory problem.
Problem is that in android 4.0 garbage colletor does not work (at least I am starting to believe so). Below is a snapshot traces from acer iconia tablet(4.0, 48M heap) and motorola defy(2.2, 30M heap) about same situation in my code. That is, get next stage from game -> ditch the old images and load new ones to memory.
4.0
08-15 21:33:07.020: V/ThemePacket(25564): debugSaveMemInfo: D:23.61 N:2.12 O:2.65
08-15 21:33:07.020: ThemePacket(25564): ClearBitmapsFromMemory: 7 friends 20 foes 2 GFIs
08-15 21:33:07.050: D/dalvikvm(25564): GC_EXPLICIT freed 4K, 74% free 10909K/41671K, paused 2ms+3ms
08-15 21:33:07.260: V/ThemePacket(25564): debugSaveMemInfo: D:23.61 N:2.12 O:2.65
08-15 21:33:07.260: V/DrawableResourceDataReference(25564): Bitmap size is: w:1875 h:1250 Asking for: w:1215 h:780
08-15 21:33:07.280: D/dalvikvm(25564): GC_FOR_ALLOC freed 36K, 74% free 10940K/41671K, paused 18ms
08-15 21:33:07.410: I/dalvikvm-heap(25564): Forcing collection of SoftReferences for 9375016-byte allocation
08-15 21:33:07.450: D/dalvikvm(25564): GC_BEFORE_OOM freed <1K, 74% free 10940K/41671K, paused 44ms
08-15 21:33:07.510: E/dalvikvm-heap(25564): Out of memory on a 9375016-byte allocation.
2.2
08-15 22:10:53.132: V/ThemePacket(15074): GetStage(1)
08-15 22:10:53.155: V/ThemePacket(15074): debugSaveMemInfo: D:2,73 N:3,36 O:15,97
08-15 22:10:53.155: V/ThemePacket(15074): ClearBitmapsFromMemory: 7 friends 20 foes 2 GFIs
08-15 22:10:53.218: D/dalvikvm(15074): GC_EXPLICIT freed 911 objects / 115904 bytes in 54ms
08-15 22:10:53.241: V/ThemePacket(15074): debugSaveMemInfo: D:2,73 N:3,36 O:9,02
08-15 22:10:53.241: V/DrawableResourceDataReference(15074): Bitmap size is: w:1875 h:1250 Asking for: w:885 h:600
08-15 22:10:53.241: V/DrawableResourceDataReference(15074): Scaling down by 2
// all goes fine
Note these lines:
debugSaveMemInfo: D:23.61 N:2.12 O:2.65
ClearBitmapsFromMemory: 7 friends 20 foes 2 GFIs
debugSaveMemInfo: D:23.61 N:2.12 O:2.6
vs.
debugSaveMemInfo: D:2,73 N:3,36 O:15,97
ClearBitmapsFromMemory: 7 friends 20 foes 2 GFIs
debugSaveMemInfo: D:2,73 N:3,36 O:9,02
And to decrypt those traces a bit, this is how I get the memory info:
Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memInfo);
double nativeMem = memInfo.nativePss/(double)1024;
double otherMem = memInfo.otherPss/(double)1024;
double dalvikMem = memInfo.dalvikPss/(double)1024;
//some formatting...
Log.v(LOG_TAG, "debugSaveMemInfo: D:" + dalvik + " N:" + nativeM + " O:" + other);
Clear bitmaps from memory beef looks like this:
// Bitmap mBitmap
mBitmap.recycle();
mBitmap = null;
and yes, I have debugged the code in both platforms and everything goes exactly the same way in my code. So if anyone is still reading this, some questions arise. Why recycling bitmaps in 4.0 does not free any memory? Isn't the GC suppose to be finding every bits of free memory before throwing OoM? If I reduce the amount of memory used totally, so that I prevent OoM, those bitmaps are eventually freed. But not when I would need the memory...
To make things more interesting, I took a hprof file from case where the ghost bitmaps are in memory and you know what, they are not! Memory analyzer says that dalvik heap is about 10M at the same moment when I print those 23M figures to the screen and get OoM from that 9M allocation. I am kind of out od ideas here so any suggestions are welcome. I guess my next solution is to lower the image quality if I get OoM
Related
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.
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
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.
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();
I'm working on an android app which fall into an infinite loop of GC_FOR_MALLOC freed :
06-15 11:24:56.685: DEBUG/dalvikvm(118): GC_FOR_MALLOC freed 4136 objects / 374744 bytes in 66ms
06-15 11:24:59.176: DEBUG/dalvikvm(521): GC_FOR_MALLOC freed 9340 objects / 524152 bytes in 645ms
06-15 11:24:59.846: DEBUG/dalvikvm(521): GC_FOR_MALLOC freed 9344 objects / 524328 bytes in 149ms
06-15 11:25:01.535: DEBUG/dalvikvm(521): GC_FOR_MALLOC freed 9346 objects / 524448 bytes in 193ms
06-15 11:25:02.175: DEBUG/dalvikvm(521): GC_FOR_MALLOC freed 9344 objects / 524344 bytes in 126ms
The application read some jpeg image over a socket (dedicated thread) and display it in a imageView. The GC loop is bloking the image display.
Is there a solution to know what line or at least what part of the code is throwing the Garbage collection ?
Thanks
I'm not sure if you can access the VM and check why it is performing gc all the time, but gc is usually performed when there is a need for it. You should check what is using so much memory. It may be loading your image (is it a big image?) or perhaps it is something else in your app. Check this post on how to analyse your memory usage and while you are at it check for memory leaks.