3

I'm writing a graphic design application for Android where the user can add several images to a document, where each image is stored as a Bitmap object. Each bitmap has roughly a dimension of 800x400 pixels and uses ARGB8888 pixel format (i.e. ~1.5Mb each).

I'm aware that most of the first generation Android devices have a 16Mb heap limit and this limit is 24Mb and larger for newer phones. I'm also aware that bitmap memory is allocated externally, but I'm confused and what the implications of this is.

My question is: How can I tell at runtime when adding a new Bitmap will get me too close to the memory limit?

Before someone suggests "don't use that much memory", I know that one option I have is to limit how many Bitmaps the user can create such that I know this limit is safe for the most basic Android phones. However, I'd like for phones with a bigger memory limit to support more bitmaps and/or bigger bitmaps.

I know to check for OutOfMemory exceptions when allocating bitmaps. However, there will be some situations where I've only got just enough memory left to allocate one more bitmap. After this point, the whole application will be unstable because even allocating small things like strings could cause an OutOfMemory exception. This is something I want to avoid.

I'm not sure how to define "too close to the memory limit", but I suspect something like "don't allocate more than half of your available memory to bitmaps" would work OK as my other data structures I store in memory are small in comparison.

  • What about `java.lang.Runtime.getRuntime.freeMemory` and `maxMemory`? Haven't tried it, though. Cheers. –  Oct 15 '10 at 16:04

2 Answers2

2

Use this method to log used memory, but I already posted that on

Android: out of memory exception in Gallery

see that post for further explanation.

public static void logHeap(Class clazz) {
    Double allocated = new Double(Debug.getNativeHeapAllocatedSize())/1048576.0);
    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.0)) + "MB of " + df.format(new Double(Runtime.getRuntime().maxMemory()/1048576.0))+ "MB (" + df.format(new Double(Runtime.getRuntime().freeMemory()/1048576.0)) +"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())/1048576.0)-MEMORY_BUFFER_LIMIT_FOR_RESTART)) {
        android.os.Process.killProcess(android.os.Process.myPid());
    }
}
Community
  • 1
  • 1
Mathias Conradt
  • 28,420
  • 21
  • 138
  • 192
  • Thanks for this! By the way, instead of e.g. "new Double(x / 122)", just write "x / 122.0" (which is a double because 122.0 is a double). The "new" creates garbage and is verbose. – heapoverflow Oct 18 '10 at 23:39
  • Just fyi, since it refers to the topic - there's a new blog post on the android blog on mem analysis: http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html – Mathias Conradt Mar 25 '11 at 03:37
0

Maybe overriding the onLowMemory class will let you do what you want to.

@Override
public void onLowMemory() {
    super.onLowMemory();
    //What you want to do
}
blindstuff
  • 18,298
  • 10
  • 47
  • 48
  • Thanks, but to clarify what I wrote in my OP, I don't want to get into the situation where I am low on memory because for stability reasons. I want to avoid getting into this situation by checking how much memory I have left before I make a big allocation. This function will just tell me when I've went too far. – heapoverflow Oct 15 '10 at 15:55
  • Sorry, cant help you then. Take a read at this, it might be a little more complicated than you expect. "bitmaps are allocated outside the VM, so you don't "see" them easily in the stats" http://stackoverflow.com/questions/2131947/android-memory-allocation – blindstuff Oct 15 '10 at 16:06
  • Thanks, I've read this post previously. I was confused too about what that means as well. – heapoverflow Oct 15 '10 at 16:13
  • 1
    I wouldn't use onLowMemory anyway: http://stackoverflow.com/questions/5329745/application-onlowmemory-not-invloked – Daniel Ryan Oct 11 '12 at 03:59