Skip to content

How to work around Android’s 24 MB memory limit

The Android framework enforces a per-process 24 MB memory limit. On some older devices, such as the G1, the limit is even lower at 16 MB.

What’s more, the memory used by Bitmaps is included in the limit. For an application manipulating images it is pretty easy to reach this limit and get the process killed with an OOM exception:

E/dalvikvm-heap(12517): 1048576-byte external allocation too large for this process.
E/GraphicsJNI(12517): VM won't let us allocate 1048576 bytes
D/AndroidRuntime(12517): Shutting down VM
W/dalvikvm(12517): threadid=1: thread exiting with uncaught exception (group=0x4001d7f0)
E/AndroidRuntime(12517): FATAL EXCEPTION: main
E/AndroidRuntime(12517): java.lang.OutOfMemoryError: bitmap size exceeds VM budget

This limit is ridiculously low. For a device, like the Nexus One, with 512MB of physical RAM, setting the per-process memory limit for the foreground activity to only 5% of the RAM is a silly mistake. But anyway, that’s how things are and we have to live with it — i.e. find how to work around it.

There are two ways to allocate much more memory than the limit:

One way is to allocate memory from native code. Using the NDK (native development kit) and JNI, it’s possible to allocate memory from the C level (e.g. malloc/free or new/delete), and such allocations are not counted towards the 24 MB limit. It’s true, allocating memory from native code is not as convenient as from Java, but it can be used to store some large amounts of data in RAM (even image data).

Another way, which works well for images, is to use OpenGL textures — the texture memory is not counted towards the limit.

To see how much memory your app has really allocated you can use android.os.Debug.getNativeHeapAllocatedSize().

Using either of the two techniques presented above, on a Nexus One, I could easily allocate 300MB for a single foreground process — more than 10 times the default 24 MB limit.

{ 16 } Comments

  1. Marius | 2010-11-21 at 16:45 | Permalink

    Discutam acum exact pe tema aceasta pe forum: http://www.androider.ro/grupuri/dezvoltatori-android/forum/topic/android-custom-view-bitmap-memory-leak/

  2. Maksym Motornyy | 2010-11-21 at 19:04 | Permalink

    Nice investigation, Mihai.

  3. Zhao Gang | 2010-11-25 at 09:22 | Permalink

    This article is great. And I have the third way to work aroud the Android memory limit.

    To create multiple services when the app lauched, and the services are deployed in other processes. (One process has 16M or 24M limited memory).
    How to deploy the service in other prcess ? An example: config the AndroidManifest.xml as below:

    Then use IPC to use the memory allocated by your services.

  4. Evgeniy | 2011-03-09 at 11:25 | Permalink

    Please, write sample how service are deployed in other processes.

  5. Homer | 2011-04-04 at 17:04 | Permalink

    As a newbie i have spent some time to understand how “OpenGL textures” represented on memory and as far as i understood they are represented as bytebuffers. If this is true would it be enough to use bytebuffers to avoid 24 mb heap size or do i have to use opengl as well ? Thanks for great blog.

  6. Rick Kawala | 2011-04-06 at 00:55 | Permalink

    So when you say we can use OpenGL textures, how much extra RAM are we talking about? Put another way, does OpenGL enforce some limit on the number and/or size of textures?

    Thanks,
    Rick

  7. Rahul | 2011-04-29 at 05:38 | Permalink

    Hi,
    Thank. This had been driving me crazy.

    Could you give me an example of how to do this?

  8. srcHG | 2011-05-03 at 09:34 | Permalink

    You sir, saved my day! Thank you very much. I’m currently developing a computer vision application for android and the memory limit was very cumbersome.

  9. Mihai Preda | 2011-05-23 at 23:05 | Permalink

    I tested on Nexus One and Motorola Milestone, and the only limit for the OpenGL total textures size is the amount of RAM. I.e. no limit on the number of textures. There are some limits on the size of any individual texture of course.

  10. Mihai Preda | 2011-05-23 at 23:09 | Permalink

    ByteBuffers are not enough, you need OpenGL as a way to get out from the Java heap.

  11. Shravan | 2011-07-18 at 06:49 | Permalink

    Thanks for your article Mihai.

    “android.os.Debug.getNativeHeapAllocatedSize()” – statement helped us monitor memory leaks in our application and explore the fixes!

  12. Peter | 2011-08-24 at 23:58 | Permalink

    wow, great post.

    will calling newByteArray in jni count towards the 24mb limit ? Or do I have to use malloc ?

    If you have any code that can be shown ( both the opengl and jni stuff ), it would be very helpful

    thanks,
    Peter

  13. Mihai Preda | 2011-08-25 at 08:16 | Permalink

    Java objects created through jni (e.g. newByteArray) are just normal java objects, thus count towards the java memory limit. You have to use malloc/free (or new/delete), which do not create java objects, to work around.

  14. Dario Marcato | 2011-11-11 at 13:16 | Permalink

    Hi! I’m trying to create a cache structure for images in native code but I’m having some trouble to find a way to allocate memory directly from c and use it for a Bitmap java object (your first method).
    Can you share some snippets of code to help me doing that?
    Thank you very much for your nice work!

  15. Santiago | 2011-12-10 at 23:22 | Permalink

    How do you create a texture from a Bitmap object?

  16. David | 2012-04-05 at 16:44 | Permalink

    Do you have any examples using OpenGL textures as you suggest?

{ 1 } Trackback

  1. [...] only real advantage of C++ for Android, aside from the lack of arbitrary memory limitations, is freedom, since JNI calls will likely slow small Apps down more the native code speeds them up. [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *