如何在Android中发现我的应用程序的内存使用情况?

时间:2010-02-19 17:12:36

标签: java android memory memory-management

如何以编程方式找到我的Android应用程序中使用的内存?

我希望有办法做到这一点。另外,我如何获得手机的免费记忆?

9 个答案:

答案 0 :(得分:992)

答案 1 :(得分:75)

是的,您可以通过编程方式获取内存信息,并决定是否进行内存密集型工作。

通过调用

获取VM堆大小
Runtime.getRuntime().totalMemory();

通过调用:

获取分配的VM内存
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

通过调用:

获取VM堆大小限制
Runtime.getRuntime().maxMemory()

通过调用:

获取本机分配的内存
Debug.getNativeHeapAllocatedSize();

我创建了一个应用程序来弄清楚OutOfMemoryError行为并监控内存使用情况。

https://play.google.com/store/apps/details?id=net.coocood.oomresearch

您可以获取源代码 https://github.com/coocood/oom-research

答案 2 :(得分:50)

这是一项正在进行的工作,但这是我不明白的地方:

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

为什么PID不映射到activityManager.getProcessMemoryInfo()中的结果?显然,您希望使得结果数据有意义,那么为什么Google难以将结果关联起来呢?如果我想处理整个内存使用情况,那么当前系统甚至不能正常工作,因为返回的结果是android.os.Debug.MemoryInfo对象的数组,但这些对象实际上都没有告诉你它们与哪些pids相关联。如果您只是传入一个包含所有pid的数组,您将无法理解结果。据我了解它的使用,它一次传递多个pid是没有意义的,然后如果是这样的话,为什么要使activityManager.getProcessMemoryInfo()只接受一个int数组?

答案 3 :(得分:24)

Hackbod是Stack Overflow的最佳答案之一。它为一个非常模糊的主题提供了亮点。它对我帮助很大。

另一个非常有用的资源是必看视频:Google I/O 2011: Memory management for Android Apps


<强>更新

Process Stats,一种发现应用管理内存的服务,由Dianne Hackborn在博客文章 Process Stats: Understanding How Your App Uses RAM 中解释:

答案 4 :(得分:19)

Android Studio 0.8.10+引入了一个名为Memory Monitor的非常有用的工具。

enter image description here

它有什么用处:

  
      
  • 在图表和垃圾收集中显示可用和已用内存   随着时间的推移。
  •   
  • 快速测试应用程序是否缓慢   与过多的垃圾收集事件有关。
  •   
  • 快速测试   应用程序崩溃是否与内存不足有关。
  •   

enter image description here

图1.在Android内存监视器上强制执行GC(垃圾收集)事件

通过使用它,您可以获得有关应用程序RAM实时消耗的大量信息。

答案 5 :(得分:16)

1)我猜不是,至少不是来自Java 2)

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

答案 6 :(得分:4)

我们发现获取当前进程总内存的所有标准方法都存在一些问题。

  • Runtime.getRuntime().totalMemory() :仅返回JVM内存
  • ActivityManager.getMemoryInfo() Process.getFreeMemory() 以及其他基于 /proc/meminfo 的内容 - 返回有关的内存信息所有过程合并在一起(例如android_util_Process.cpp
  • Debug.getNativeHeapAllocatedSize() - 使用mallinfo()返回有关malloc()及相关功能执行的内存分配的信息(请参阅android_os_Debug.cpp
  • Debug.getMemoryInfo() - 完成工作,但速度太慢了。单次通话 Nexus 6 需要 200ms 。性能开销使得这个功能对我们来说毫无用处,因为我们经常调用它并且每个调用都非常明显(参见android_os_Debug.cpp
  • ActivityManager.getProcessMemoryInfo(int[]) - 在内部致电Debug.getMemoryInfo()(请参阅ActivityManagerService.java

最后,我们最终使用了以下代码:

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;

返回 VmRSS 指标。您可以在此处找到有关它的更多详细信息:onetwothree

PS 我注意到主题仍然缺少如何估计进程的私有内存使用情况的实际和简单的代码片段,如果性能不是'一个关键要求:

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;

答案 7 :(得分:0)

上面有很多答案肯定对你有所帮助,但是(经过2天的adb记忆工具的研究和开发)我想我可以帮助我的意见也是。

作为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. ,因此您无法获得每个进程的确切内存量。

但是你可以通过一些逻辑来接近它......我将告诉你如何......

  

上面提到了一些像android.os.Debug.MemoryInfoActivityManager.getMemoryInfo()这样的API,您可能已经阅读并使用了这些API,但我会谈谈其他方式

首先,您需要成为root用户才能使其正常运行。通过在进程中执行su进入具有root权限的控制台并获取其output and input stream。然后在ouputstream中传递id\n (输入)并将其写入流程输出,如果获得包含uid=0的输入流,您是root用户。

现在这里是您将在上述过程中使用的逻辑

当您获得进程的ouputstream 通过\n而不是id 传递您的命令(procrank,dumpsys meminfo等...)并获取其inputstream并读取,存储以字节[],char []等方式使用的流..使用原始数据......你就完成了!!!!!

许可:

<uses-permission android:name="android.permission.FACTORY_TEST"/>

检查您是否是root用户:

// 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
   } 
}

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

logcat: result

  

您可以从控制台获取单个字符串中的原始数据,而不是来自任何API的原始数据,因为您需要手动将其分开,因此存储起来很复杂。

这只是一次尝试,如果我错过了某些内容,请建议我

答案 8 :(得分:0)

在android studio 3.0中,他们引入了android-profiler来帮助您了解您的应用如何使用CPU,内存,网络和电池资源。

https://developer.android.com/studio/profile/android-profiler

enter image description here