views:

106

answers:

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.

+1  A: 

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
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
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
Thanks, I've read this post previously. I was confused too about what that means as well.
heapoverflow
A: 

What about java.lang.Runtime.getRuntime.freeMemory and maxMemory? Haven't tried it, though.

Cheers.

Shaot
A: 

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

http://stackoverflow.com/questions/3238388/android-out-of-memory-exception-in-gallery/3238945#3238945

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());
    }
}
Mathias Lin
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
thanks, i corrected it.
Mathias Lin