How do I discover memory usage of my application in Android?
如何以编程方式找到我的Android应用程序上使用的内存?
我希望有办法做到这一点。 另外,我如何获得手机的免费记忆?
请注意,像Linux这样的现代操作系统上的内存使用是一个非常复杂且难以理解的领域。事实上,你实际正确地解释你得到的任何数字的可能性非常低。 (几乎每次我与其他工程师一起查看内存使用数字时,总会有很长时间讨论它们实际上意味着什么只会导致模糊的结论。)
注意:我们现在有更多关于管理您的应用程序内存的文档,其中涵盖了大部分内容,并且更新了Android的最新状态。
首先要阅读本文的最后一部分,其中讨论了如何在Android上管理内存:
从Android 2.0开始的服务API更改
现在
在较低级别,您可以使用Debug API获取有关内存使用情况的原始内核级信息:android.os.Debug.MemoryInfo
注意从2.0开始,还有一个API
这将返回包含所有这些数据的低级MemoryInfo结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /** 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; |
但至于
Android(以及一般的Linux系统)中的大量内存实际上是在多个进程之间共享的。那么进程使用多少内存实际上并不清楚。将该页面分页添加到磁盘(更不用说我们在Android上不使用的交换),它甚至不太清楚。
因此,如果您将实际映射到的每个物理RAM都放到每个进程中,并将所有进程相加,那么最终可能会得到比实际总RAM大得多的数字。
另一个有趣的指标是
这就是SDK API。但是,作为开发人员,您可以使用设备做更多事情。
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ** MEMINFO in pid 890 [system] ** native dalvik other total size: 10940 7047 N/A 17987 allocated: 8943 5516 N/A 14459 free: 336 1531 N/A 1867 (Pss): 4585 9282 11916 25783 (shared dirty): 2184 3596 916 6696 (priv dirty): 4504 5956 7456 17916 Objects Views: 149 ViewRoots: 4 AppContexts: 13 Activities: 0 Assets: 4 AssetManagers: 4 Local Binders: 141 Proxy Binders: 158 Death Recipients: 49 OpenSSL Sockets: 0 SQL heap: 205 dbFiles: 0 numPagers: 0 inactivePageKB: 0 activePageKB: 0 |
顶部是主要部分,其中
如果您只想查看所有进程的内存使用情况,可以使用命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | PID Vss Rss Pss Uss cmdline 890 84456K 48668K 25850K 21284K system_server 1231 50748K 39088K 17587K 13792K com.android.launcher2 947 34488K 28528K 10834K 9308K com.android.wallpaper 987 26964K 26956K 8751K 7308K com.google.process.gapps 954 24300K 24296K 6249K 4824K com.android.phone 948 23020K 23016K 5864K 4748K com.android.inputmethod.latin 888 25728K 25724K 5774K 3668K zygote 977 24100K 24096K 5667K 4340K android.process.acore ... 59 336K 332K 99K 92K /system/bin/installd 60 396K 392K 93K 84K /system/bin/keystore 51 280K 276K 74K 68K /system/bin/servicemanager 54 256K 252K 69K 64K /system/bin/debuggerd |
这里的
这里有趣的事情是:
最后是命令
1 2 3 4 5 | MemTotal: 395144 kB MemFree: 184936 kB Buffers: 880 kB Cached: 84104 kB SwapCached: 0 kB |
好。
是的,您可以通过编程方式获取内存信息,并决定是否进行内存密集型工作。
通过调用获取VM堆大小:
1 |
通过调用以获取分配的VM内存:
通过调用以获取VM堆大小限制:
1 |
通过调用获取本机分配的内存:
1 | Debug.getNativeHeapAllocatedSize(); |
我做了一个应用程序来弄清楚OutOfMemoryError行为并监视内存使用情况。
https://play.google.com/store/apps/details?id=net.coocood.oomresearch
你可以在那里获得源代码
https://github.com/coocood/oom-research
这是一项正在进行的工作,但这是我不明白的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | ActivityManager activityManager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE); MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); activityManager.getMemoryInfo(memoryInfo); Log.i(TAG," memoryInfo.availMem" + memoryInfo.availMem +" " ); Log.i(TAG," memoryInfo.lowMemory" + memoryInfo.lowMemory +" " ); Log.i(TAG," memoryInfo.threshold" + memoryInfo.threshold +" " ); 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] ** ",pids[0],pidMap.get(pids[0]))); Log.i(TAG," pidMemoryInfo.getTotalPrivateDirty():" + pidMemoryInfo.getTotalPrivateDirty() +" "); Log.i(TAG," pidMemoryInfo.getTotalPss():" + pidMemoryInfo.getTotalPss() +" "); Log.i(TAG," pidMemoryInfo.getTotalSharedDirty():" + pidMemoryInfo.getTotalSharedDirty() +" "); } } |
为什么PID不映射到activityManager.getProcessMemoryInfo()中的结果?显然,您希望使得结果数据有意义,那么为什么Google难以将结果关联起来呢?如果我想处理整个内存使用情况,那么当前系统甚至不能正常工作,因为返回的结果是android.os.Debug.MemoryInfo对象的数组,但这些对象实际上都没有告诉你它们与哪些pids相关联。如果您只是传入一个包含所有pid的数组,您将无法理解结果。据我了解它的使用,它一次传递多个pid是没有意义的,然后如果是这样的话,为什么要使activityManager.getProcessMemoryInfo()只接受一个int数组?
Hackbod是Stack&nbsp; Overflow的最佳答案之一。它为一个非常模糊的主题提供了亮点。这对我帮助很大。
另一个非常有用的资源是这个必看的视频:Google I / O 2011:Android应用程序的内存管理
更新:
Process Stats,一种发现应用管理内存的服务,在博客文章中解释过程统计:了解你的应用如何使用RAM由Dianne Hackborn:
Android Studio 0.8.10+引入了一个名为Memory Monitor的非常有用的工具。
它有什么好处:
- 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.
图1.在Android内存监视器上强制执行GC(垃圾收集)事件
通过使用它,您可以获得有关应用程序RAM实时消耗的大量信息。
1)我猜不是,至少不是来自Java
2)
1 2 3 4 | ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); MemoryInfo mi = new MemoryInfo(); activityManager.getMemoryInfo(mi); Log.i("memory free","" + mi.availMem); |
我们发现获取当前进程总内存的所有标准方法都存在一些问题。
-
Runtime.getRuntime().totalMemory() :仅返回JVM内存 -
ActivityManager.getMemoryInfo() ,Process.getFreeMemory() 以及基于/proc/meminfo 的任何其他内容 - 返回有关所有进程组合的内存信息(例如android_util_Process.cpp) -
Debug.getNativeHeapAllocatedSize() - 使用mallinfo() 返回有关malloc() 和相关函数执行的内存分配的信息(请参阅android_os_Debug.cpp) -
Debug.getMemoryInfo() - 完成工作,但速度太慢。一次通话需要大约200毫秒的Nexus 6。性能开销使得这个函数对我们来说没用,因为我们经常调用它并且每次调用都非常明显(参见android_os_Debug.cpp) -
ActivityManager.getProcessMemoryInfo(int[]) - 在内部调用Debug.getMemoryInfo() (请参阅ActivityManagerService.java)
最后,我们最终使用以下代码:
1 2 3 4 5 6 7 8 9 | const long pageSize = 4 * 1024; //`sysconf(_SC_PAGESIZE)` string stats = File.ReadAllText("/proc/self/statm"); var statsArr = stats.Split(new [] {' ', '\t', ' '}, 3); if( statsArr.Length < 2 ) throw new Exception("Parsing error of /proc/self/statm:" + stats); return long.Parse(statsArr[1]) * pageSize; |
它返回VmRSS指标。您可以在此处找到有关它的更多详细信息:一,二和三。
附:我注意到,如果性能不是关键要求,主题仍然缺乏如何估计进程的私有内存使用情况的实际和简单的代码片段:
1 2 3 4 5 6 7 8 | 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; |
在android studio 3.0中,他们引入了android-profiler来帮助您了解您的应用程序如何使用CPU,内存,网络和电池资源。
https://developer.android.com/studio/profile/android-profiler
上面有很多答案肯定会对你有所帮助,但是(经过2天的adb记忆工具的研究和开发)我觉得我也可以帮助我。
正如Hackbod所说:因此,如果您将实际映射到的每个物理RAM都放到每个进程中,并将所有进程加起来,那么最终可能会得到比实际总RAM大得多的数字。所以你无法获得每个进程的确切内存量。
但是你可以通过一些逻辑来接近它......我将告诉你如何......
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
首先,您需要成为root用户才能使其正常工作。通过在进程中执行
现在,这是您将在上述过程中使用的逻辑
当你获得进程的ouputstream时,用
许可:
1 | <uses-permission android:name="android.permission.FACTORY_TEST"/> |
检查您是否是root用户:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // 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 "); dataOutputStream.flush(); String Uid = dataInputStream.readLine(); // read output and check if uid is there if (Uid.contains("uid=0")) { // you are root user } } |
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | Process process = Runtime.getRuntime().exec("su"); DataOutputStream dataOutputStream = new DataOutputStream(process.getOutputStream()); if (dataOutputStream != null) { // adb command dataOutputStream.writeBytes("procrank "); 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:
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.
这只是一个尝试,如果我错过了什么请建议我