Rectangle 27 0

java How do I discover memory usage of my application in Android?


Debug.getNativeHeapAllocatedSize();
Runtime.getRuntime().maxMemory()
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

@mahemadhi from the JavaDoc of totalMemory() method "Returns the total amount of memory which is available to the running program"

Does this runtime will return memory usage by current process or overall system heap ?

I made an app to figure out the OutOfMemoryError behavior and monitor memory usage.

Yes, you can get memory info programmatically and decide whether to do memory intensive work.

Note
Rectangle 27 0

java How do I discover memory usage of my application in Android?


ActivityManager activityManager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);

Log.i(TAG, " memoryInfo.availMem " + memoryInfo.availMem + "\n" );
Log.i(TAG, " memoryInfo.lowMemory " + memoryInfo.lowMemory + "\n" );
Log.i(TAG, " memoryInfo.threshold " + memoryInfo.threshold + "\n" );

List<RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();

Map<Integer, String> pidMap = new TreeMap<Integer, String>();
for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses)
{
    pidMap.put(runningAppProcessInfo.pid, runningAppProcessInfo.processName);
}

Collection<Integer> keys = pidMap.keySet();

for(int key : keys)
{
    int pids[] = new int[1];
    pids[0] = key;
    android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
    for(android.os.Debug.MemoryInfo pidMemoryInfo: memoryInfoArray)
    {
        Log.i(TAG, String.format("** MEMINFO in pid %d [%s] **\n",pids[0],pidMap.get(pids[0])));
        Log.i(TAG, " pidMemoryInfo.getTotalPrivateDirty(): " + pidMemoryInfo.getTotalPrivateDirty() + "\n");
        Log.i(TAG, " pidMemoryInfo.getTotalPss(): " + pidMemoryInfo.getTotalPss() + "\n");
        Log.i(TAG, " pidMemoryInfo.getTotalSharedDirty(): " + pidMemoryInfo.getTotalSharedDirty() + "\n");
    }
}

Fair enough. I'm trying to write an internal tool to track memory usage for one or more of the applications we're writing. As a result, I'm looking for a way to do this monitoring while impacting the other processes the least, but still being as detailed with the results as possible (post-processing). Iterating over the processes, and then making calls for each process seems to be inefficient, assuming there is some overhead for each .getProcessMemoryInfo call. If the returned array is guaranteed to be in the same order as the call, I'll process the results blindly and just assume parity.

That seems like a very non-intuitive way to do things. Yes, that probably is the case, but how is that in any way OOP?

The API was designed for efficiency, not ease of use or simplicity. This is just not something that 99% of apps should ever touch, so efficiency is the most important design goal.

They're likely in the same order as the input array.

This is a minor issue, but for Log, it isn't necessary to add a linefeed, that is handled for you.

This is a work in progress, but this is what I don't understand:

Why isn't the PID mapped to the result in activityManager.getProcessMemoryInfo()? Clearly you want to make the resulting data meaningful, so why has Google made it so difficult to correlate the results? The current system doesn't even work well if I want to process the entire memory usage since the returned result is an array of android.os.Debug.MemoryInfo objects, but none of those objects actually tell you what pids they are associated with. If you simply pass in an array of all pids, you will have no way to understand the results. As I understand it's use, it makes it meaningless to pass in more than one pid at a time, and then if that's the case, why make it so that activityManager.getProcessMemoryInfo() only takes an int array?

Note
Rectangle 27 0

java How do I discover memory usage of my application in Android?


/** The proportional set size for dalvik. */
    public int dalvikPss;
    /** The private dirty pages used by dalvik. */
    public int dalvikPrivateDirty;
    /** The shared dirty pages used by dalvik. */
    public int dalvikSharedDirty;

    /** The proportional set size for the native heap. */
    public int nativePss;
    /** The private dirty pages used by the native heap. */
    public int nativePrivateDirty;
    /** The shared dirty pages used by the native heap. */
    public int nativeSharedDirty;

    /** The proportional set size for everything else. */
    public int otherPss;
    /** The private dirty pages used by everything else. */
    public int otherPrivateDirty;
    /** The shared dirty pages used by everything else. */
    public int otherSharedDirty;
ActivityManager.getProcessMemoryInfo

Note: we now have much more extensive documentation on Managing Your App's Memory that covers much of the material here and is more up-to-date with the state of Android.

A lot of memory in Android (and Linux systems in general) is actually shared across multiple processes. So how much memory a processes uses is really not clear. Add on top of that paging out to disk (let alone swap which we don't use on Android) and it is even less clear.

But as to what the difference is between Pss, PrivateDirty, and SharedDirty... well now the fun begins.

Cached is the RAM being used for filesystem caches and other such things. Typical systems will need to have 20MB or so for this to avoid getting into bad paging states; the Android out of memory killer is tuned for a particular system to make sure that background processes are killed before the cached RAM is consumed too much by them to result in such paging.

Finally there is the command adb shell cat /proc/meminfo that gives a summary of the overall memory usage of the system. There is a lot of data here, only the first few numbers worth discussing (and the remaining ones understood by few people, and my questions of those few people about them often resulting in conflicting explanations):

First thing is to probably read the last part of this article which has some discussion of how memory is managed on Android:

Going lower-level, you can use the Debug API to get raw kernel-level information about memory usage: android.os.Debug.MemoryInfo

Have a look at pixelbeat.org/scripts/ps_mem.py which uses the techniques mentioned above to show used RAM for programs

Here the Vss and Rss columns are basically noise (these are the straight-forward address space and RAM usage of a process, where if you add up the RAM usage across processes you get an ridiculously large number).

I can use "adb shell dumpsys meminfo",but "adb shell procrank tell me "/system/bin/sh: procrank: not found". I haven't a clue.Wish you can help me.

If you just want to look at memory usage across all processes, you can use the command adb shell procrank. Output of this on the same system looks like:

Interesting thing to note here: Pss and Uss are slightly (or more than slightly) different than what we saw in meminfo. Why is that? Well procrank uses a different kernel mechanism to collect its data than meminfo does, and they give slightly different results. Why is that? Honestly I haven't a clue. I believe procrank may be the more accurate one... but really, this just leave the point: "take any memory info you get with a grain of salt; often a very large grain."

MemFree is the amount of RAM that is not being used at all. The number you see here is very high; typically on an Android system this would be only a few MB, since we try to use available memory to keep processes running

MemTotal is the total amount of memory available to the kernel and user space (often less than the actual physical RAM of the device, since some of that RAM is needed for the radio, DMA buffers, etc).

Note that memory usage on modern operating systems like Linux is an extremely complicated and difficult to understand area. In fact the chances of you actually correctly interpreting whatever numbers you get is extremely low. (Pretty much every time I look at memory usage numbers with other engineers, there is always a long discussion about what they actually mean that only results in a vague conclusion.)

Now ActivityManager.getMemoryInfo() is our highest-level API for looking at overall memory usage. This is mostly there to help an application gauge how close the system is coming to having no more memory for background processes, thus needing to start killing needed processes like services. For pure Java applications, this should be of little use, since the Java heap limit is there in part to avoid one app from being able to stress the system to this point.

Pss is as we've seen before, and Uss is Priv Dirty.

That is pretty much the SDK APIs for this. However there is more you can do as a developer with your device.

The Pss number is a metric the kernel computes that takes into account memory sharing -- basically each page of RAM in a process is scaled by a ratio of the number of other processes also using that page. This way you can (in theory) add up the pss across all processes to see the total RAM they are using, and compare pss between processes to get a rough idea of their relative weight.

The other interesting metric here is PrivateDirty, which is basically the amount of RAM inside the process that can not be paged to disk (it is not backed by the same data on disk), and is not shared with any other processes. Another way to look at this is the RAM that will become available to the system when that process goes away (and probably quickly subsumed into caches and other uses of it).

The top section is the main one, where size is the total size in address space of a particular heap, allocated is the kb of actual allocations that heap thinks it has, free is the remaining kb free the heap has for additional allocations, and pss and priv dirty are the same as discussed before specific to pages associated with each of the heaps.

This returns a low-level MemoryInfo structure with all of this data:

Thus if you were to take all of the physical RAM actually mapped in to each process, and add up all of the processes, you would probably end up with a number much greater than the actual total RAM.

Using adb, there is a lot of information you can get about the memory use of a running system. A common one is the command adb shell dumpsys meminfo which will spit out a bunch of information about the memory use of each Java process, containing the above info as well as a variety of other things. You can also tack on the name or pid of a single process to see, for example adb shell dumpsys meminfo system give me the system process:

Very nice written! I wrote a post on memory management and use of different tools to inspect your heap usage here macgyverdev.blogspot.com/2011/11/ if anyone finds it useful.

What exactly are "native" "dalvik" "other"? In my app, "other" is very huge? how can I reduce it?

What exactly are the two columns "dalvik" an "native"?

Note
Rectangle 27 0

java How do I discover memory usage of my application in Android?


Hackbod's is one of the best answers on StackOverflow. It throws light on a very obscure subject. It helped me a lot.

Note
Rectangle 27 0

java How do I discover memory usage of my application in Android?


  • Quickly testing whether app crashes may be related to running out of memory.
  • Showing available and used memory in a graph, and garbage collection events over time.

Figure 1. Forcing a GC (Garbage Collection) event on Android Memory Monitor

You can have plenty good information on your app's RAM real-time consumption by using it.

Note
Rectangle 27 0

java How do I discover memory usage of my application in Android?


ActivityManager.getProcessMemoryInfo(int[])
Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
Debug.getMemoryInfo(memInfo);
long res = memInfo.getTotalPrivateDirty();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
    res += memInfo.getTotalPrivateClean(); 

return res * 1024L;
Debug.getMemoryInfo()
const long pageSize = 4 * 1024; //`sysconf(_SC_PAGESIZE)`
string stats = File.ReadAllText("/proc/self/statm");
var statsArr = stats.Split(new [] {' ', '\t', '\n'}, 3);

if( statsArr.Length < 2 )
    throw new Exception("Parsing error of /proc/self/statm: " + stats);

return long.Parse(statsArr[1]) * pageSize;
  • ActivityManager.getMemoryInfo(), Process.getFreeMemory() and anything else based on /proc/meminfo - returns memory info about all the processes combined (e.g. android_util_Process.cpp)
  • Debug.getMemoryInfo() - does the job but it's too slow. It takes about 200ms on Nexus 6 for a single call. The performance overhead makes this function useless for us as we call it regularly and every call is quite noticeable (see android_os_Debug.cpp)
  • Debug.getNativeHeapAllocatedSize() - uses mallinfo() which return information about memory allocations performed by malloc() and related functions only (see android_os_Debug.cpp)
  • Runtime.getRuntime().totalMemory(): returns JVM memory only

Finally, we ended up using the following code:

It returns VmRSS metric. You can find more details about it here: one, two and three.

P.S. I noticed that the theme still has a lack of an actual and simple code snippet of how to estimate the private memory usage of the process if the performance isn't a critical requirement:

We found out that all the standard ways of getting the total memory of the current process have some issues.

Note
Rectangle 27 0

java How do I discover memory usage of my application in Android?


ActivityManager activityManager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);

Log.i(TAG, " memoryInfo.availMem " + memoryInfo.availMem + "\n" );
Log.i(TAG, " memoryInfo.lowMemory " + memoryInfo.lowMemory + "\n" );
Log.i(TAG, " memoryInfo.threshold " + memoryInfo.threshold + "\n" );

List<RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();

Map<Integer, String> pidMap = new TreeMap<Integer, String>();
for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses)
{
    pidMap.put(runningAppProcessInfo.pid, runningAppProcessInfo.processName);
}

Collection<Integer> keys = pidMap.keySet();

for(int key : keys)
{
    int pids[] = new int[1];
    pids[0] = key;
    android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
    for(android.os.Debug.MemoryInfo pidMemoryInfo: memoryInfoArray)
    {
        Log.i(TAG, String.format("** MEMINFO in pid %d [%s] **\n",pids[0],pidMap.get(pids[0])));
        Log.i(TAG, " pidMemoryInfo.getTotalPrivateDirty(): " + pidMemoryInfo.getTotalPrivateDirty() + "\n");
        Log.i(TAG, " pidMemoryInfo.getTotalPss(): " + pidMemoryInfo.getTotalPss() + "\n");
        Log.i(TAG, " pidMemoryInfo.getTotalSharedDirty(): " + pidMemoryInfo.getTotalSharedDirty() + "\n");
    }
}

Fair enough. I'm trying to write an internal tool to track memory usage for one or more of the applications we're writing. As a result, I'm looking for a way to do this monitoring while impacting the other processes the least, but still being as detailed with the results as possible (post-processing). Iterating over the processes, and then making calls for each process seems to be inefficient, assuming there is some overhead for each .getProcessMemoryInfo call. If the returned array is guaranteed to be in the same order as the call, I'll process the results blindly and just assume parity.

That seems like a very non-intuitive way to do things. Yes, that probably is the case, but how is that in any way OOP?

The API was designed for efficiency, not ease of use or simplicity. This is just not something that 99% of apps should ever touch, so efficiency is the most important design goal.

They're likely in the same order as the input array.

This is a minor issue, but for Log, it isn't necessary to add a linefeed, that is handled for you.

This is a work in progress, but this is what I don't understand:

Why isn't the PID mapped to the result in activityManager.getProcessMemoryInfo()? Clearly you want to make the resulting data meaningful, so why has Google made it so difficult to correlate the results? The current system doesn't even work well if I want to process the entire memory usage since the returned result is an array of android.os.Debug.MemoryInfo objects, but none of those objects actually tell you what pids they are associated with. If you simply pass in an array of all pids, you will have no way to understand the results. As I understand it's use, it makes it meaningless to pass in more than one pid at a time, and then if that's the case, why make it so that activityManager.getProcessMemoryInfo() only takes an int array?

Note
Rectangle 27 0

java How do I discover memory usage of my application in Android?


ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
activityManager.getMemoryInfo(mi);
Log.i("memory free", "" + mi.availMem);

change to (ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);) instead of (ActivityManager activityManager = = (ActivityManager) getSystemService(ACTIVITY_SERVICE);)

Note
Rectangle 27 0

java How do I discover memory usage of my application in Android?


ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
activityManager.getMemoryInfo(mi);
Log.i("memory free", "" + mi.availMem);

change to (ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);) instead of (ActivityManager activityManager = = (ActivityManager) getSystemService(ACTIVITY_SERVICE);)

Note
Rectangle 27 0

java How do I discover memory usage of my application in Android?


Debug.getNativeHeapAllocatedSize();
Runtime.getRuntime().maxMemory()
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

Does this runtime will return memory usage by current process or overall system heap ?

I made an app to figure out the OutOfMemoryError behavior and monitor memory usage.

Yes, you can get memory info programmatically and decide whether to do memory intensive work.

Note