How to tell how close your activity is to reaching

2020-06-24 02:26发布

问题:

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:

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());
    }
}


回答2:

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

@Override
public void onLowMemory() {
    super.onLowMemory();
    //What you want to do
}