How can I find the memory used on my Android application, programmatically?
I hope there is a way to do it. Plus, how do I get the free memory of the phone too?
This question is related to
java
android
memory
memory-management
1) I guess not, at least not from Java.
2)
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
activityManager.getMemoryInfo(mi);
Log.i("memory free", "" + mi.availMem);
In android studio 3.0 they have introduced android-profiler to help you to understand how your app uses CPU, memory, network, and battery resources.
https://developer.android.com/studio/profile/android-profiler
We found out that all the standard ways of getting the total memory of the current process have some issues.
Runtime.getRuntime().totalMemory()
: returns JVM memory onlyActivityManager.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.getNativeHeapAllocatedSize()
- uses mallinfo()
which return information about memory allocations performed by malloc()
and related functions only (see android_os_Debug.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)ActivityManager.getProcessMemoryInfo(int[])
- calls Debug.getMemoryInfo()
internally (see ActivityManagerService.java)Finally, we ended up using the following code:
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;
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:
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;
This is a work in progress, but this is what I don't understand:
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");
}
}
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?
There are a lot of answer above which will definitely help you but (after 2 days of afford and research on adb memory tools) I think i can help with my opinion too.
As Hackbod says : 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. so there is no way you can get exact amount of memory per process.
But you can get close to it by some logic..and I will tell how..
There are some API like
android.os.Debug.MemoryInfo
andActivityManager.getMemoryInfo()
mentioned above which you already might have being read about and used but I will talk about other way
So firstly you need to be a root user to get it work. Get into console with root privilege by executing su
in process and get its output and input stream
. Then pass id\n
(enter) in ouputstream and write it to process output, If will get an inputstream containing uid=0
, you are root user.
Now here is the logic which you will use in above process
When you get ouputstream of process pass you command (procrank, dumpsys meminfo etc...) with \n
instead of id and get its inputstream
and read, store the stream in bytes[ ] ,char[ ] etc.. use raw data..and you are done!!!!!
permission :
<uses-permission android:name="android.permission.FACTORY_TEST"/>
Check if you are root user :
// su command to get root access
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dataOutputStream =
new DataOutputStream(process.getOutputStream());
DataInputStream dataInputStream =
new DataInputStream(process.getInputStream());
if (dataInputStream != null && dataOutputStream != null) {
// write id to console with enter
dataOutputStream.writeBytes("id\n");
dataOutputStream.flush();
String Uid = dataInputStream.readLine();
// read output and check if uid is there
if (Uid.contains("uid=0")) {
// you are root user
}
}
Execute your command with su
Process process = Runtime.getRuntime().exec("su");
DataOutputStream dataOutputStream =
new DataOutputStream(process.getOutputStream());
if (dataOutputStream != null) {
// adb command
dataOutputStream.writeBytes("procrank\n");
dataOutputStream.flush();
BufferedInputStream bufferedInputStream =
new BufferedInputStream(process.getInputStream());
// this is important as it takes times to return to next line so wait
// else you with get empty bytes in buffered stream
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// read buffered stream into byte,char etc.
byte[] bff = new byte[bufferedInputStream.available()];
bufferedInputStream.read(bff);
bufferedInputStream.close();
}
}
You get a raw data in a single string from console instead of in some instance from any API,which is complex to store as you will need to separate it manually.
This is just a try, please suggest me if I missed something
Android Studio 0.8.10+ has introduced an incredibly useful tool called Memory Monitor.
What it's good for:
- Showing available and used memory in a graph, and garbage collection events over time.
- Quickly testing whether app slowness might be related to excessive garbage collection events.
- Quickly testing whether app crashes may be related to running out of memory.
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.
Yes, you can get memory info programmatically and decide whether to do memory intensive work.
Get VM Heap Size by calling:
Runtime.getRuntime().totalMemory();
Get Allocated VM Memory by calling:
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
Get VM Heap Size Limit by calling:
Runtime.getRuntime().maxMemory()
Get Native Allocated Memory by calling:
Debug.getNativeHeapAllocatedSize();
I made an app to figure out the OutOfMemoryError behavior and monitor memory usage.
https://play.google.com/store/apps/details?id=net.coocood.oomresearch
You can get the source code at https://github.com/coocood/oom-research
Hackbod's is one of the best answers on Stack Overflow. It throws light on a very obscure subject. It helped me a lot.
Another really helpful resource is this must-see video: Google I/O 2011: Memory management for Android Apps
UPDATE:
Process Stats, a service to discover how your app manages memory explained at the blog post Process Stats: Understanding How Your App Uses RAM by Dianne Hackborn:
Source: Stackoverflow.com