Reputation: 39721
I've got an app which fetches bitmaps in threads, then puts the bitmaps into a global mem cache. On a 2.2 emulator, I get a reproducable out-of-memory error after loading enough bitmaps (they're in a listview):
FATAL EXCEPTION: pool-1-thread-1
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
...
The heap looks stable (3.3mb), and I wonder if I can't see the amount of memory growing because I think in the 2.2 os, bitmap memory is stored separately? I keep doing hprof dumps and viewing them in MAT, and my object counts look as expected.
Running the app on an ICS phone doesn't exhibit the same problem (yet, maybe just has more memory etc). I think in the later OSs they keep bitmap memory as part of the heap?
In either case, is there a way to see which Bitmap instances have been allocated by my app? The hprof dumps just show a total count system-wide I think. But I can't see where they were allocated from.
I'm using:
android.support.v4.util.LruCache<String, Bitmap>
as a memcache - it almost seems like the bitmap data isn't being cleaned up after entries get evicted (I set the cache to have a 5mb cap). I remember there being methods on Bitmap like recycle(), maybe they're not getting cleaned up properly?
Thanks
Upvotes: 1
Views: 444
Reputation: 6929
you are right later versions keep the bitmap data in the native heap. But even so this data still counts against the bitmap budget. To avoid this error you must call recycle! So extend LruCache, override entryRemoved
and call recycle in there.
Additionally I would put a limit to the cache depending on the device memory. You could for example use ActivityManager.getMemoryClass()
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
int memoryClass = activityManager.getMemoryClass();
memoryClass
contains the dalvik heap in megabytes. You could for example use 1/5 of that value as a limit for the cache.
Still this might not be sufficient to avoid the OOM-Error since the bitmap memory is only freed in the finalizer. Be sure to read up the official doc about bitmap handling. If all that fails you can still try call System.gc()
in entryRemoved
and see if that helps. But as Ewoks pointed out, this is not only bad practice but may also cause the UI-Thread to stop for some time so only do this as a very last resort.
Upvotes: 1
Reputation: 30168
The heap looks stable (3.3mb), and I wonder if I can't see the amount of memory growing because I think in the 2.2 os, bitmap memory is stored separately? I keep doing hprof dumps and viewing them in MAT, and my object counts look as expected.
Correct, for 2.x you can't see the memory the bitmaps are taking with MAT (you could do the dump from the ICS device and suddenly see a huge jump). However, the amount of memory available is the same (depends from device to device though, it's between 16 MB and 32 MB, in general). The solution is to keep as few bitmaps in memory as possible. You might get away with keeping them in memory if they were only thumbnail sized, but in general you just can't load that many.
Upvotes: 1