148

How do you programmatically detect the application heap size available to an Android app?

I heard there's a function that does this in later versions of the SDK. In any case, I'm looking for solution that works for 1.5 and upwards.

hpique
  • 112,774
  • 126
  • 328
  • 461
  • 2
    Related: http://stackoverflow.com/questions/1518154/what-is-the-objective-of-setting-the-minimum-heap-size-in-an-android-app – Josh Lee Oct 12 '10 at 17:29

9 Answers9

456

There are two ways to think about your phrase "application heap size available":

  1. How much heap can my app use before a hard error is triggered? And

  2. How much heap should my app use, given the constraints of the Android OS version and hardware of the user's device?

There is a different method for determining each of the above.

For item 1 above: maxMemory()

which can be invoked (e.g., in your main activity's onCreate() method) as follows:

Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));

This method tells you how many total bytes of heap your app is allowed to use.

For item 2 above: getMemoryClass()

which can be invoked as follows:

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));

This method tells you approximately how many megabytes of heap your app should use if it wants to be properly respectful of the limits of the present device, and of the rights of other apps to run without being repeatedly forced into the onStop() / onResume() cycle as they are rudely flushed out of memory while your elephantine app takes a bath in the Android jacuzzi.

This distinction is not clearly documented, so far as I know, but I have tested this hypothesis on five different Android devices (see below) and have confirmed to my own satisfaction that this is a correct interpretation.

For a stock version of Android, maxMemory() will typically return about the same number of megabytes as are indicated in getMemoryClass() (i.e., approximately a million times the latter value).

The only situation (of which I am aware) for which the two methods can diverge is on a rooted device running an Android version such as CyanogenMod, which allows the user to manually select how large a heap size should be allowed for each app. In CM, for example, this option appears under "CyanogenMod settings" / "Performance" / "VM heap size".

NOTE: BE AWARE THAT SETTING THIS VALUE MANUALLY CAN MESS UP YOUR SYSTEM, ESPECIALLY if you select a smaller value than is normal for your device.

Here are my test results showing the values returned by maxMemory() and getMemoryClass() for four different devices running CyanogenMod, using two different (manually-set) heap values for each:

  • G1:
    • With VM Heap Size set to 16MB:
      • maxMemory: 16777216
      • getMemoryClass: 16
    • With VM Heap Size set to 24MB:
      • maxMemory: 25165824
      • getMemoryClass: 16
  • Moto Droid:
    • With VM Heap Size set to 24MB:
      • maxMemory: 25165824
      • getMemoryClass: 24
    • With VM Heap Size set to 16MB:
      • maxMemory: 16777216
      • getMemoryClass: 24
  • Nexus One:
    • With VM Heap size set to 32MB:
      • maxMemory: 33554432
      • getMemoryClass: 32
    • With VM Heap size set to 24MB:
      • maxMemory: 25165824
      • getMemoryClass: 32
  • Viewsonic GTab:
    • With VM Heap Size set to 32:
      • maxMemory: 33554432
      • getMemoryClass: 32
    • With VM Heap Size set to 64:
      • maxMemory: 67108864
      • getMemoryClass: 32

In addition to the above, I tested on a Novo7 Paladin tablet running Ice Cream Sandwich. This was essentially a stock version of ICS, except that I've rooted the tablet through a simple process that does not replace the entire OS, and in particular does not provide an interface that would allow the heap size to be manually adjusted.

For that device, here are the results:

  • Novo7
    • maxMemory: 62914560
    • getMemoryClass: 60

Also (per Kishore in a comment below):

  • HTC One X
    • maxMemory: 67108864
    • getMemoryClass: 64

And (per akauppi's comment):

  • Samsung Galaxy Core Plus
    • maxMemory: (Not specified in comment)
    • getMemoryClass: 48
    • largeMemoryClass: 128

Per a comment from cmcromance:

  • Galaxy S3 (Jelly Bean) large heap
    • maxMemory: 268435456
    • getMemoryClass: 64

And (per tencent's comments):

  • LG Nexus 5 (4.4.3) normal
    • maxMemory: 201326592
    • getMemoryClass: 192
  • LG Nexus 5 (4.4.3) large heap
    • maxMemory: 536870912
    • getMemoryClass: 192
  • Galaxy Nexus (4.3) normal
    • maxMemory: 100663296
    • getMemoryClass: 96
  • Galaxy Nexus (4.3) large heap
    • maxMemory: 268435456
    • getMemoryClass: 96
  • Galaxy S4 Play Store Edition (4.4.2) normal
    • maxMemory: 201326592
    • getMemoryClass: 192
  • Galaxy S4 Play Store Edition (4.4.2) large heap
    • maxMemory: 536870912
    • getMemoryClass: 192

Other Devices

  • Huawei Nexus 6P (6.0.1) normal
    • maxMemory: 201326592
    • getMemoryClass: 192

I haven't tested these two methods using the special android:largeHeap="true" manifest option available since Honeycomb, but thanks to cmcromance and tencent we do have some sample largeHeap values, as reported above.

My expectation (which seems to be supported by the largeHeap numbers above) would be that this option would have an effect similar to setting the heap manually via a rooted OS - i.e., it would raise the value of maxMemory() while leaving getMemoryClass() alone. There is another method, getLargeMemoryClass(), that indicates how much memory is allowable for an app using the largeHeap setting. The documentation for getLargeMemoryClass() states, "most applications should not need this amount of memory, and should instead stay with the getMemoryClass() limit."

If I've guessed correctly, then using that option would have the same benefits (and perils) as would using the space made available by a user who has upped the heap via a rooted OS (i.e., if your app uses the additional memory, it probably will not play as nicely with whatever other apps the user is running at the same time).

Note that the memory class apparently need not be a multiple of 8MB.

We can see from the above that the getMemoryClass() result is unchanging for a given device/OS configuration, while the maxMemory() value changes when the heap is set differently by the user.

My own practical experience is that on the G1 (which has a memory class of 16), if I manually select 24MB as the heap size, I can run without erroring even when my memory usage is allowed to drift up toward 20MB (presumably it could go as high as 24MB, although I haven't tried this). But other similarly large-ish apps may get flushed from memory as a result of my own app's pigginess. And, conversely, my app may get flushed from memory if these other high-maintenance apps are brought to the foreground by the user.

So, you cannot go over the amount of memory specified by maxMemory(). And, you should try to stay within the limits specified by getMemoryClass(). One way to do that, if all else fails, might be to limit functionality for such devices in a way that conserves memory.

Finally, if you do plan to go over the number of megabytes specified in getMemoryClass(), my advice would be to work long and hard on the saving and restoring of your app's state, so that the user's experience is virtually uninterrupted if an onStop() / onResume() cycle occurs.

In my case, for reasons of performance I'm limiting my app to devices running 2.2 and above, and that means that almost all devices running my app will have a memoryClass of 24 or higher. So I can design to occupy up to 20MB of heap and feel pretty confident that my app will play nice with the other apps the user may be running at the same time.

But there will always be a few rooted users who have loaded a 2.2 or above version of Android onto an older device (e.g., a G1). When you encounter such a configuration, ideally, you ought to pare down your memory use, even if maxMemory() is telling you that you can go much higher than the 16MB that getMemoryClass() is telling you that you should be targeting. And if you cannot reliably ensure that your app will live within that budget, then at least make sure that onStop() / onResume() works seamlessly.

getMemoryClass(), as indicated by Diane Hackborn (hackbod) above, is only available back to API level 5 (Android 2.0), and so, as she advises, you can assume that the physical hardware of any device running an earlier version of the OS is designed to optimally support apps occupying a heap space of no more than 16MB.

By contrast, maxMemory(), according to the documentation, is available all the way back to API level 1. maxMemory(), on a pre-2.0 version, will probably return a 16MB value, but I do see that in my (much later) CyanogenMod versions the user can select a heap value as low as 12MB, which would presumably result in a lower heap limit, and so I would suggest that you continue to test the maxMemory() value, even for versions of the OS prior to 2.0. You might even have to refuse to run in the unlikely event that this value is set even lower than 16MB, if you need to have more than maxMemory() indicates is allowed.

Dick Lucas
  • 10,721
  • 9
  • 44
  • 71
Carl
  • 14,895
  • 5
  • 52
  • 53
  • 2
    @Carl Hello Carl, Thank you for your great post. And I tested option, android:largeHeap="true" on Galaxy S3 with JellyBean. Here is the result. [maxMemory:256.0MB , memoryClass:64MB] (maxMemory was 64MB without the largeheap option) – cmcromance Sep 04 '13 at 08:19
  • @cmcromance: Thanks for that information! I've incorporated your results, with credit, into the text of my post. – Carl Sep 04 '13 at 22:33
  • 1
    @Carl Haha It's a great honor! :) – cmcromance Sep 05 '13 at 00:35
  • 1
    For HTC One X : maxMemory:67108864 memoryClass:64 – Kishore Nov 06 '13 at 06:44
  • how do you get the heap size (used and total) of another app (meaning not your app) ? is it even possible ? – android developer Jan 14 '14 at 09:07
  • I don't know of a way to do that. Why would you need the heap size of another app? – Carl Jan 16 '14 at 03:20
  • does the emulator use the same amount of heap size memory as the phone/tablet they are emulating for a particular app? I seem get the max heap size error crash very quickly on the emulator emulating a tablet. I can't afford an actual tablet to test, so was wondering if the emulator used more heap. – Androidcoder Mar 23 '14 at 14:09
  • @michael: this is controlled by the Max VM application heap size property, which can be changed when you edit your AVD. Just change that value from whatever it is now (e.g., 48) to something larger (e.g., 128). Also, make sure that you have enough RAM in the Device Definition that your AVD is using. – Carl Mar 23 '14 at 21:41
  • Samsung Galaxy Core Plus: memoryClass 48, largeMemoryClass 128 – akauppi Apr 09 '14 at 14:41
  • 1
    LG Nexus 5 (4.4.3) (normal): maxMemory: 201326592, memoryClass:192 | LG Nexus 5 (4.4.3) (large heap): maxMemory: 536870912, memoryClass:192 – ian.shaun.thomas Jun 04 '14 at 14:54
  • Galaxy Nexus (4.3) (normal): maxMemory: 100663296, memoryClass:96 | Galaxy Nexus (4.3) (large heap): maxMemory: 268435456, memoryClass:96 – ian.shaun.thomas Jun 04 '14 at 14:59
  • Galaxy S4 Play Store Edition (4.4.2) (normal): maxMemory: 201326592, memoryClass:192 | Galaxy S4 Play Store Edition (4.4.2) (large heap): maxMemory: 536870912, memoryClass:192 – ian.shaun.thomas Jun 04 '14 at 15:02
  • Thanks for detailed information. One question please. Lets say the heap size is 16MB. But if i try to load a bitmap of size for example 2000x1400 having size of 2-4 MB. The Out of memory exception is going to be raised regardless of the available heap. Why is that? – Muhammad Babar May 25 '15 at 06:03
  • "On Android 2.3.3 (API level 10) and lower, the backing pixel data for a bitmap is stored in native memory. It is separate from the bitmap itself, which is stored in the Dalvik heap. The pixel data in native memory is not released in a predictable manner, potentially causing an application to briefly exceed its memory limits and crash. As of Android 3.0 (API level 11), the pixel data is stored on the Dalvik heap along with the associated bitmap." https://developer.android.com/training/displaying-bitmaps/manage-memory.html – Carl Jun 22 '15 at 03:14
  • 1
    Very beautifully documented. Please provide this to android. I cannot find such appropriate Android document – Jimit Patel Nov 06 '15 at 11:39
  • Galaxy Tab A (9.0) maxMemory: 268435456, memoryClass:256 – SteveS Nov 21 '19 at 00:54
20

The official API is:

This was introduced in 2.0 where larger memory devices appeared. You can assume that devices running prior versions of the OS are using the original memory class (16).

Alex Lockwood
  • 81,274
  • 37
  • 197
  • 245
hackbod
  • 88,517
  • 16
  • 135
  • 152
14

Here's how you do it:

Getting the max heap size that the app can use:

Runtime runtime = Runtime.getRuntime();
long maxMemory=runtime.maxMemory();

Getting how much of the heap your app currently uses:

long usedMemory=runtime.totalMemory() - runtime.freeMemory();

Getting how much of the heap your app can now use (available memory) :

long availableMemory=maxMemory-usedMemory;

And, to format each of them nicely, you can use:

String formattedMemorySize=Formatter.formatShortFileSize(context,memorySize); 
android developer
  • 106,412
  • 122
  • 641
  • 1,128
13

Debug.getNativeHeapSize() will do the trick, I should think. It's been there since 1.0, though.

The Debug class has lots of great methods for tracking allocations and other performance concerns. Also, if you need to detect a low-memory situation, check out Activity.onLowMemory().

Neil Traft
  • 16,833
  • 15
  • 58
  • 68
  • Thanks Neil. Does this work when the application is running with debugging turned off? – hpique Apr 13 '10 at 23:00
  • 4
    I'm fairly new to this, but I don't think that the native heap is the same as the app (Dalvik) heap to which the question refers. The native heap provides backing for bitmap data, which is allocated by native code, while the app heap holds Java application data. I was interested to learn that the native heap is counted against the app heap's limit, and after 3.0 the allocations actually occur on the app's heap. Diane Hackborn (hackbod) posts on this topic here: http://stackoverflow.com/questions/1945142/bitmaps-in-android But even for 3.0, there is also non-"native" data on the app heap. – Carl Feb 24 '12 at 21:34
  • 1
    Since some recent Android update (maybe KitKat 4.4) the bitmaps are in JVM heap. – akauppi Apr 09 '14 at 14:36
6

This returns max heap size in bytes:

Runtime.getRuntime().maxMemory()

I was using ActivityManager.getMemoryClass() but on CyanogenMod 7 (I didn't test it elsewhere) it returns wrong value if the user sets heap size manually.

fhucho
  • 31,862
  • 40
  • 125
  • 178
  • Since the doc for `getMemoryClass` seems to imply that the number may not be the same as the available heap size for your vm, and since the doc for `getNativeHeapSize` is... taciturn, I really think `Runtime.getRuntime().maxMemory()` is the best answer. – BoD Dec 06 '11 at 17:13
2

Some operations are quicker than java heap space manager. Delaying operations for some time can free memory space. You can use this method to escape heap size error:

waitForGarbageCollector(new Runnable() {
  @Override
  public void run() {
    // Your operations.
  }
});

/**
 * Measure used memory and give garbage collector time to free up some
 * of the space.
 *
 * @param callback Callback operations to be done when memory is free.
 */
public static void waitForGarbageCollector(final Runnable callback) {

  Runtime runtime;
  long maxMemory;
  long usedMemory;
  double availableMemoryPercentage = 1.0;
  final double MIN_AVAILABLE_MEMORY_PERCENTAGE = 0.1;
  final int DELAY_TIME = 5 * 1000;

  runtime =
    Runtime.getRuntime();

  maxMemory =
    runtime.maxMemory();

  usedMemory =
    runtime.totalMemory() -
    runtime.freeMemory();

  availableMemoryPercentage =
    1 -
    (double) usedMemory /
    maxMemory;

  if (availableMemoryPercentage < MIN_AVAILABLE_MEMORY_PERCENTAGE) {
    try {
      Thread.sleep(DELAY_TIME);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    waitForGarbageCollector(
      callback);
  } else {
    // Memory resources are available, go to next operation:
    callback.run();
  }
}
Void
  • 851
  • 1
  • 9
  • 12
Zon
  • 12,838
  • 4
  • 69
  • 82
  • tested Good. Can you Elaborate these two things : availableMemoryPercentage and MIN_AVAILABLE_MEMORY_PERCENTAGE ? some Explanations ? – Noor Hossain Jul 04 '19 at 21:35
  • 1
    `AvailableMemoryPercentage` is according to formula: how much of device's memory is currently free. `MIN_AVAILABLE_MEMORY_PERCENTAGE` is your custom parameter, a threshold at which you start waiting for garbage collector to do its job. – Zon Jul 07 '19 at 17:41
1

Asus Nexus 7 (2013) 32Gig: getMemoryClass()=192 maxMemory()=201326592

I made the mistake of prototyping my game on the Nexus 7, and then discovering it ran out of memory almost immediately on my wife's generic 4.04 tablet (memoryclass 48, maxmemory 50331648)

I'll need to restructure my project to load fewer resources when I determine memoryclass is low.
Is there a way in Java to see the current heap size? (I can see it clearly in the logCat when debugging, but I'd like a way to see it in code to adapt, like if currentheap>(maxmemory/2) unload high quality bitmaps load low quality

0
Runtime rt = Runtime.getRuntime();
rt.maxMemory()

value is b

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.getMemoryClass()

value is MB

qinqie
  • 57
  • 6
0

Do you mean programatically, or just while you're developing and debugging? If the latter, you can see that info from the DDMS perspective in Eclipse. When your emulator (possibly even physical phone that is plugged in) is running, it will list the active processes in a window on the left. You can select it and there's an option to track the heap allocations.

Steve Haley
  • 53,826
  • 17
  • 73
  • 84
  • I mean programmatically. Clarified the question. Thanks. – hpique Apr 13 '10 at 16:08
  • 1
    I suggest you look at this post by one of the Android platform programmers then: http://stackoverflow.com/questions/2298208/how-to-discovery-memory-usage-on-my-application-in-android/2299813#2299813 – Steve Haley Apr 14 '10 at 10:36