Bitmaps in Android
Asked Answered
B

4

29

I have a few questions regarding Bitmap objects and memory and their general taxonomy.

  1. What is an in-memory or native bitmap?
  2. How is Bitmap memory different from Heap memory?
Brabble answered 22/12, 2009 at 9:20 Comment(0)
C
33

The memory that backs a Bitmap object is allocated using native code (malloc()), rather than the Java new keyword. This means that the memory is managed directly by the OS, rather than by Dalvik.

The only real difference between the native heap and Dalvik's heap is that Dalvik's heap is garbage collected, and the native one isn't.

For these purposes though, here's not much difference. When your Bitmap object gets garbage collected, it's destructor will recycle the associated memory in the native heap.

Source:

Colas answered 22/12, 2009 at 19:27 Comment(3)
Do you know if this bug was ever fixed? I'm currently running into the same problem on the thunder bolt. I'm recycling the bitmaps but they're never clearing any space on the native heap causing oom errors.Merge
Just for clarity, the above answer is true for android version 2.x and below. Starting with Android 3, bitmap instances are counter agains the heap. This can easily be checked: creating a bitmap in android 2.x will leave the Java heap size pretty much intouched, creating it in Adnroid 3.x will add a lot of bytes to the Java heap.Breathe
Ah! so you are saying the counting is now much more intuitive? That's great - except for all of us who wrote hacky code to sum the android heap with the native heap ...Brail
P
33

There is an important subtlety here: though Bitmap pixels are allocated in the native heap, some special tricks in Dalvik cause it to be accounted against the Java heap. This is done for two reasons:

(1) To control the amount of memory an application allocates this. Without the accounting, an application could allocate a huge amount of memory (since the Bitmap object itself is very small yet can hold on to an arbitrarily large amount of native memory), extending beyond the 16MB or 24MB heap limit.

(2) To help determine when to GC. Without the accounting, you could allocate and release references on say 100 Bitmap objects; the GC wouldn't run, because these objects are tiny, but they could in fact represent a large number of megabytes of actual allocations that is now not being GCed in a timely manner. By accounting these allocations against the Java heap, the garbage collector will run as it thinks memory is being used.

Note that in many ways this is an implementation detail; it is very likely that it could change in the future, though this basic behavior would remain in some form since these are both important characteristics for managing bitmap allocations.

Provincial answered 22/12, 2009 at 21:14 Comment(4)
Even on phones which count bitmaps against the java heap, native malloc can allocate WAY more than 16 MiB.Brail
The first comment is wrong, all phones count bitmap allocations against the Dalvik heap limit. The main change to be aware of is that as of Android 3.0 the allocations are actually done in the Dalvik heap, so you no longer have to deal with situations where the GC would not run as aggressively as it should.Provincial
you are right on that point. Still, the GC is retarded when it comes to dealing with recycled bitmaps. I've found unpredictable behavior unless I manually run the GC after recycling a bitmap (including the tendency for the next "load" to return a copy of the recycled bitmap instead of actually loading it from disk)Brail
@Provincial ...as of Android 3.0 the allocations are actually done in the Dalvik heap... So, recycle() is useless ? AFAIK you can't always invoke GC precisely on command.Score
B
13

From deployments in the wild, I've found the following devices:

  • Devices that limit to 16 MiB of java heap (bitmaps are nearly unlimited).
  • Devices that limit to 16 MiB of (java heap + native bitmap storage)
  • Devices that limit to 24 MiB of java heap (bitmaps are nearly unlimited).
  • Devices that limit to 24 MiB of (java heap + native bitmap storage)

24 MiB tends to be the high res devices, and can be detected with Runtime.getRuntime().maxMemory(). There's also 32MiB devices now, and some of the rooted phones have 64MiB by default. Previously, I confused my self several times trying to work out what was happening. I think all devices count bitmaps into the heap limit. But it's wildly difficult to make any sweeping generalizations about the android fleet.

This is a VERY nasty issue on Android, and very confusing. This limit and it's behaviors are poorly documented, complicated, and extremely non-intuitive. They also vary across devices and OS versions, and have several known bugs. Part of the problem is that the limits are not precise - due to heap fragmentation, you will hit OOM well before the actual limit and must conservatively leave a meg or two of buffer. Even worse, I've got several devices where there is a native segfault (100% a bug in Android itself) that occurs before you get the java OOM exception, making it doubly important to never reach the limit since you can't even catch the native crash. For more details on my investigations, check out this post. In the same post, I explain how to measure usage against the limit and avoid crashes.

The size of the java heap is Runtime.getRuntime().totalMemory().

There is no easy way to measure the size of the native bitmap storage. The overall native heap can be measure with Debug.getNativeHeapAllocatedSize(), but only the bitmaps count toward the limit (i think).

Brail answered 18/2, 2011 at 5:49 Comment(4)
Since anyone can release their own version of Android, it seems quite believable that there could be versions out there that implement different policies for limiting heap memory, including those that you describe above. CyanogenMod, for example, allows users to set the heap limit themselves, so I don't see why there could not be an OS release that implements the policies regarding limits that you describe. I'd be interested to know whether there are any official guidelines in this regard. If not, then we're subject to the whims of those OS variants.Estray
@Carl. From what I can tell, it's pure chaos. Though in general, the mods and rooted phones tend to increase the heap limits, typically to 64M. The decision to so severely limit Java heap size was brain-dead retarded and results in horrible user experiences.Brail
It does force us as developers to take a hard look at our use of memory. I am presently developing an app that has a very large data set that must reside entirely on the heap (because of an intensive search process), and my original String array-based implementation took up 15 MB of heap for that data alone (each String ref in the array takes 32 bytes of data). After nearly hitting the 24 MB limit that a lot of current devices still impose, I designed a custom data structure that takes only 3.5MB to hold exactly the same information. Now my app will run even on a device with a 16MB limit.Estray
@Estray - I took a dictionary with 180k words avg length 10 chars (15M to store as Java strings), and crammed it into 400k. :) The issue is that it's really really hard to reduce bitmap memory since any proprietary storage format would be incompatible with the native rendering code. That, and it seems very silly to make memory artificially expensive on a device that has half a gig of physical ram. And where native code can allocate 1+G with no complaints from the OS. It's just a way of punishing Java developers.Brail
L
-1

We can increase the heap size by using android:largeheap="true" in your manifest file. This will solve your some problem.

Llama answered 28/11, 2013 at 5:35 Comment(1)
Think about your users battery... Requesting a largeheap to cover some mistakes on memory allocations, clearly can't be a solution.Paulino

© 2022 - 2024 — McMap. All rights reserved.