Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: how to increase heap size at runtime?

I have an image cache in my application which is implemented using SoftReferences. Dalvik starts applications with relatively small heap, and then increases it in case of demand. But I'd like to have my heap size bigger from the beginning. That is because when I already have some images in the cache, and an activity starts (for example) or other peak memory demand occurs, my cache gets purged in order to let memory for that peak demand. As a result, after the peak is gone I still have 2-3 MB of free space but my cache is empty!

The solution I see for this trouble is pre-allocating a bigger heap forehand so even with the peak consumption of 2-3 MBs it still has some roomspace so my SoftReferences are not purged.

I found that VMRuntime.getRuntime().setMinimumHeapSize(BIGGER_SIZE) would be helpful. In particular, Google uses that in their apps, as mentioned here. However, VMRuntime class is marked deprecated and said to be removed from the public API in a future release. So setMinimumHeapSize is not a permanent solution.

How then I make Dalvik to grow my heap at startup?

Currently I use a really straight-forward and cheesy technique by just allocating a large array and releasing it. This makes Dalvik grow the heap as I want. However, I'm sure there must be more elegant way of doing that. Could you tell me that, please?

like image 223
JBM Avatar asked Nov 07 '10 19:11

JBM


2 Answers

Instead of increasing heap size you can do some thing better. As you said that you are maintaining cache in you application which is implemented using SoftReferences. The best thing is to use LruCache you can do some thing like this:

private LruCache<String, Bitmap> bitmapCache;
final int memClass;
int cacheSize;

memClass = ((ActivityManager) context.getSystemService(
    Context.ACTIVITY_SERVICE)).getMemoryClass();

Return the approximate per-application memory class of the current device. This gives you an idea of how hard a memory limit you should impose on your application to let the overall system work best. The returned value is in megabytes; the baseline Android memory class is 16 (which happens to be the Java heap limit of those devices); some device with more memory may return 24 or even higher numbers.

cacheSize = 1024 * 1024 * memClass / 10;
bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
  @Override
  protected int sizeOf(String key, Bitmap value) {
    return value.getHeight() * value.getRowBytes();
 }
};

it will remove the bitmap images from LruCache if the memory exceeds the located memory to LruCache and load the new image in it.

like image 99
Suru Avatar answered Oct 09 '22 08:10

Suru


If the cache is ususally small as you say, you can decide a valid footprint of your app by yourself and maintain your own cache without SoftReferences.

For example by a simple total byte counter: Just add or move any element used to the top of a list, add its size to the counter if it is new. Delete from the bottom if the total bytes exceed your rule-of-thumb limit, thereby decreasing your counter. Maybe the LinkedHashMap class is useful for that: It can be used as a cache like a HashMap, but it has an order too like a list.

like image 27
dronus Avatar answered Oct 09 '22 08:10

dronus