java.lang.OutOfMemoryError: bitmap size exceeds VM budget

Need to vent on the bane of all my Android code. Apart from one release that contained an unfortunate bug that I didn’t catch, at least 80% of all the force closes I see are caused by the above error; the remaining force closes being almost always caused by code that has been implemented to prevent the above error.

Has anyone got some good tips on how to avoid this? Google’s official stance seems to be “use smaller bitmaps” as well as denial of claims that Android leaks resources; in other words, no help at all. I know exactly the amount of graphics that should be loaded in memory and - it’s large - but nowhere near 16mb. I can note down some of the steps that I’ve used that have reduced the problem a lot - though not eliminated it entirely.

  • Large bitmaps loaded using Bitmap.Config.RGB_565 ( = smaller size).
  • All the bitmaps loaded up front in a centralized ImageLibrary class. This ensures that no large bitmaps are loaded more than once, and that all the bitmaps are explicitly recycled and nulled when the application switches out.
  • In general, the code is gone through with a fine tooth comb to prevent any form of memory leaks. Difficult to guarantee none, of course, but there is definitely no large scale mem leaks left.
  • Explicit call of System.gc() when cleaning out/redrawing large bitmaps. Ugly and slow, but every little thing helps.
  • Bitmapfactory.decodeResources (which has a reputation for memory leaks) is cleaned out of the code. Removing those calls seemed to reduce out of memory errors a good deal (though perhaps I am just imagining things). I am contemplating removing bitmaps out of the layouts as well now, as that is presumably the only place left where Bitmapfactory is being used.

Anyone knows of any tricks I’ve missed?

System.gc() is one of the first things i delete when i see it on a project.

Anyway guess the emulator has no memory profiler right?

Yep, that’s pretty much it. I didn’t try Bitmap.Config.RGB_565. Does that really make a difference?

I’m not using System.gc() because I like to do so. And I’m not even convinced it does much (as I understand it, bitmaps are treated specially in the VM). But every little bit helps, and my app doesn’t require animation. :frowning:

It is possible to do memory profiling of the Android processes, but because of the aforementioned issue (i.e., special treatment for bitmaps), it’s not really all that useful to solve this problem.

@kingaschi:
RGB_565 should pretty much halve the memory footprint of your bitmaps (16bit versus 32bit). As I recall, the logcat also confirmed that this was the case, so yes. Note though it does mean no transparency.

I don’t think calling the System.gc() would help in this case . Before failing because a memory shortage, the GC will try to free some memory .
The System.gc() call is useful if you want to free up some memory before starting a new stage for example, to make sure it won’t run in the middle of the action and slow things down .

But as for your problem, I really don’t know what can help . I never ran into such problems in my games, but I never really used lots and lots of bitmaps . Maybe make sure everything that might refer to this bitmap is really gone ? (i.e. a Canvas)

Is there no RGB4444?

Cas :slight_smile:

Show the freemem on screen live, and you might be wiser.

If you are 100% sure this is due to graphics only, one must try to split up bigger pieces into tilesets.
For one game we pretty much cut anything with a horizontal or vertical stretch into endbits and tiled 1px-wide middle strips
to eke out everything we could out of the Series40 mobile limits.

However, it seems you know how much graphics you have. And you have the profiler: if the profiler + gfx goes over your limit,
the problem is in the code after all perhaps?

Are you loading the images in order of size (largest first)?
If the memory occupied by the images is being flagged as unmovable for gc purposes this should reduce the impact of the fragmentation.

Back in the day this is an issue that many of the more frustrating J2ME phones suffered from (predominantly Motorolas); though by now I would hope Android phones would be more sophisticated.

Have you tried using SoftReferences for referencing the bitmaps?

This way the GC should clear out references before you run out of memory.
Combined with a lazy loading mechanism this will give you more memory to work with, at the expense of more IO and decoding ofcourse. :slight_smile:

http://developer.android.com/reference/java/lang/ref/SoftReference.html

@princec: There is indeed an RGB_4444 that could also be used. :slight_smile:

@Karmington: It’s (fairly) easy to see how much memory is being used by the android program itself. In my case, it is nowhere near the limit and there is no memory leak apparent at all in the main code itself. There might be a memory leak in my use of bitmap though I would be rather surprised if there was, considering the number of times I’ve gone over that code to recycle and null everything. It’s not that big and complex a program.

The problem is rather obfuscated (as no one seems to be able to find the exact issue); but the best “explanation” I’ve read yet suggests that the problem in Android is that the Dalvik VM doesn’t keep track of the native heap (which is where bitmaps are stored) and doesn’t garbage collect there. The result being that bitmap data that has actually been recycled/deleted in the VM may linger for awhile before it is garbage collected by whatever process administrates the native heap. Unfortunately I’ve yet to see Google even acknowledge that there is a problem.

@Abuse: Yep.

@C-A-D: Unfortunately, the way I use graphics, that method really shouldn’t work (I already purge graphics aggressively once they are no longer needed). Might be worth experimenting with it though…

Thanks for all the suggestions and thoughts.

maybe you could try to make a “test prog” that load and free a lot of bitmap to validate or invalidate that possible VM memory bug ?

The problem has been discussed a number of times on the android lists/forums, so I don’t think there is much question that there is a bug. It’s easy enough to provoke if you load one or two large bitmaps and do something like deallocating/reallocating the resources in onPause/onResume. Doing all the stuff I mentioned above helps reduce the problem to some extent, but doesn’t solve it entirely.

Actually I’d say it should be tested with and without.
If it works better with, then leave it in.
Why?
While I have no experience with Android I do have a lot with j2me mobiles and in some cases it could actually help.
Along with other crazy/strange stuff (f.i. after ‘loading’ a resource, a s.o.p with the handle would assure it is fully loaded)
Don’t ask me why, it just did.

[quote]The problem has been discussed a number of times on the android lists/forums, so I don’t think there is much question that there is a bug.
[/quote]
Perhaps not, but a bug report with a small test case usually go a long way in making sure a problem is getting fixed.

What are you using instead now?

I load the drawable and then draw it to an empty bitmap. Fairly similar to what Robert Green does in this code snippet.

Note that many of the worst issues seem to have been fixed with OS 2.1 - I note, for instance, that the case where an extended View (one can make a very basic extends of View to demonstrate it) leaks when switching between ContentViews in the same activity is no longer a problem in 2.1 (below 2.1, though, you get orphaned objects). Without having dug into it in detail (which - as mentioned - is very difficult, as we don’t have access to the bitmap heap), the resource handling seems to work better on 2.1 - though perhaps I’m just seeing the consequence of general bug fixes to the framework like the stuff mentioned above.

Thanks, i’ll play around with that to see if it helps.

An important recommendation (if you haven’t already done this), is to take a heap dump of your app after operating it for some length of time, and running it through the memory analyzer, looking for duplicates objects (especially your own). Because of all the callbacks in the Android GUI code, it is actually fairly easy to leak GUI objects - and that can quickly eat up mem.

Actually, it’s an application with a deterministic behaviour and memory consumption. It starts at A) and runs over B) and C) to D), where it exits. It’s a benchmark (this one: http://www.jpct.net/jpct-ae/download/alpha/bench/Benchmark-AE.apk). It’s memory consumption shouldn’t exceed 7+mb. However, from time to time, it’s unable to create some Bitmaps even if it’s nowhere near 16mb. This isn’t a huge problem because it happens very seldom and maybe only on my phone (Galaxy, Android 1.5), but i would like to see this fixed anyway. The change from BitmapFactory to Drawable didn’t do any good. It’s nice to have the option anyway…

The benchmark functions very modestly for most of the benchmark (3-6Mb of heap on the 1.5 emulator), but when you hit the last part of the benchmark (Game Level), I’m registering heap usage of between 14000 - 17000 kb (using procrank). With that kind of resource usage, you shouldn’t be surprised if it crashes out of memory every now and then as that doesn’t give you a a lot of leeway.

On a hdpi 2.2 emulator it peaks at around 19mb, which gives you a little more than 4mb of heap space.