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.
/** 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;
有趣的是这里需要注意的是: Pss 和 Uss 与我们在 meminfo 中看到的略有不同(或稍微不同) . 这是为什么?那么procrank使用不同的内核机制来收集它的数据,而不是 meminfo ,它们给出的结果略有不同 . 这是为什么?老实说,我没有任何线索 . 我相信 procrank 可能更准确......但实际上,这只是留下了重点:"take any memory info you get with a grain of salt; often a very large grain."
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;
首先,您需要成为root用户才能使其正常工作 . 通过在进程中执行 su 进入具有root权限的控制台并获取其 output and input stream . 然后在ouputstream中传递 id\n (输入)并将其写入过程输出,如果将获得输入流包含 uid=0 , you are root user.
现在,这是您将在上述过程中使用的逻辑
当您获得进程 pass you command (procrank, dumpsys meminfo etc...) with \n instead of id 的ouputstream并获取其 inputstream 并读取时,将该流存储在bytes [],char []等中..使用 raw data..and您已完成!!!!!
// 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();
}
}
8 回答
请注意,像Linux这样的现代操作系统上的内存使用是一个非常复杂且难以理解的领域 . 事实上,你实际正确地解释你得到的任何数字的可能性非常低 . (几乎每次我与其他工程师一起查看内存使用数字时,总会有很长时间讨论它们实际上意味着什么只会导致模糊的结论 . )
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.
首先要阅读本文的最后一部分,其中讨论了如何在Android上管理内存:
Service API changes starting with Android 2.0
现在
ActivityManager.getMemoryInfo()
是我们用于查看总体内存使用情况的最高级API . 这主要是为了帮助应用程序测量系统与后台进程没有更多内存的接近程度,从而需要开始杀死所需的进程,如服务 . 对于纯Java应用程序,这应该没用,因为Java堆限制部分是为了避免一个应用程序能够强调系统到此为止 .更低级别,您可以使用Debug API获取有关内存使用情况的原始内核级信息:android.os.Debug.MemoryInfo
注意从2.0开始,还有一个API,
ActivityManager.getProcessMemoryInfo
,用于获取有关另一个进程的信息:ActivityManager.getProcessMemoryInfo(int[])这将返回包含所有这些数据的低级MemoryInfo结构:
但至于
Pss
,PrivateDirty
和SharedDirty
之间的区别是什么......现在好玩的开始了 .Android(以及一般的Linux系统)中的大量内存实际上是在多个进程之间共享的 . 因此,进程使用多少内存实际上并不清楚 . 将该页面分页添加到磁盘(更不用说我们在Android上不使用的交换),它甚至不太清楚 .
因此,如果您将实际映射到的每个物理RAM都放到每个进程中,并将所有进程相加,那么最终可能会得到比实际总RAM大得多的数字 .
Pss
数字是内核计算的一个度量,它考虑了内存共享 - 基本上每个进程中的RAM页面都按照使用该页面的其他进程数量的比例进行缩放 . 通过这种方式,您可以(在理论上)将pss添加到所有进程中以查看它们正在使用的总RAM,并比较进程之间的pss以大致了解它们的相对权重 .另一个有趣的指标是
PrivateDirty
,它基本上是进程内部无法分页到磁盘的RAM数量(它不受磁盘上相同数据的支持),并且不与任何其他进程共享 . 另一种看待这种情况的方法是当该进程消失时系统可用的RAM(并且可能很快被包含在缓存和其它用途中) .这就是SDK API . 但是,作为开发人员,您可以使用设备做更多事情 .
使用
adb
,您可以获得有关正在运行的系统的内存使用的大量信息 . 常见的一个是命令adb shell dumpsys meminfo
,它会发出一堆关于每个Java进程的内存使用情况的信息,包含上述信息以及其他各种信息 . 您还可以查看单个进程的名称或pid以查看,例如adb shell dumpsys meminfo system
给我系统进程:顶部是主要部分,其中
size
是特定堆的地址空间中的总大小,allocated
是堆认为它具有的实际分配的kb,free
是堆具有用于其他分配的剩余kb,以及pss
和priv dirty
与之前讨论的相同,特定于与每个堆相关联的页面 .如果您只想查看所有进程的内存使用情况,可以使用命令
adb shell procrank
. 在同一系统上输出的内容如下:这里的
Vss
和Rss
列基本上都是噪声(这些是进程的直接地址空间和RAM使用情况,如果你将进程间的RAM使用量加起来就会得到一个非常大的数字) .Pss
就像我们以前见过的那样,Uss
是Priv Dirty
.有趣的是这里需要注意的是:
Pss
和Uss
与我们在meminfo
中看到的略有不同(或稍微不同) . 这是为什么?那么procrank使用不同的内核机制来收集它的数据,而不是meminfo
,它们给出的结果略有不同 . 这是为什么?老实说,我没有任何线索 . 我相信procrank
可能更准确......但实际上,这只是留下了重点:"take any memory info you get with a grain of salt; often a very large grain."最后是命令
adb shell cat /proc/meminfo
,它给出了系统总内存使用情况的摘要 . 这里有很多数据,只有最初的几个数字值得讨论(其余的数据很少被人理解,我对这些人的问题经常导致相互矛盾的解释):MemTotal
是内核和用户空间可用的内存总量(通常小于设备的实际物理RAM,因为无线电,DMA缓冲区等需要一些RAM) .MemFree
是根本没有使用的RAM量 . 你在这里看到的数字非常高;通常在Android系统上,这只有几MB,因为我们尝试使用可用内存来保持进程运行Cached
是用于文件系统缓存和其他此类事物的RAM . 为此,典型系统需要大约20MB才能避免陷入错误的寻呼状态;针对特定系统调整Android内存不足以确保后台进程在缓存的RAM被其过多消耗之前被杀死以导致此类分页 .是的,您可以通过编程方式获取内存信息,并决定是否进行内存密集型工作 .
通过调用获取VM堆大小:
通过调用以获取分配的VM内存:
通过调用以获取VM堆大小限制:
通过调用获取本机分配的内存:
我做了一个应用程序来弄清楚OutOfMemoryError行为并监视内存使用情况 .
https://play.google.com/store/apps/details?id=net.coocood.oomresearch
您可以在https://github.com/coocood/oom-research获取源代码
这是一项正在进行中的工作,但这是我不明白的:
为什么PID不映射到activityManager.getProcessMemoryInfo()中的结果?显然,您希望使得结果数据有意义,那么为什么Google难以将结果关联起来呢?如果我想处理整个内存使用情况,当前系统甚至不能正常工作,因为返回的结果是android.os.Debug.MemoryInfo对象的数组,但这些对象实际上都没有告诉你它们与哪些pids相关联 . 如果您只是传入所有pid的数组,则无法理解结果 . 据我了解它的使用,它一次传递多个pid是没有意义的,然后如果是这样的话,为什么要使activityManager.getProcessMemoryInfo()只接受一个int数组?
Hackbod是Stack Overflow上最好的答案之一 . 它为一个非常模糊的主题提供了亮点 . 这对我帮助很大 .
另一个非常有用的资源是必看视频:Google I/O 2011: Memory management for Android Apps
UPDATE:
Process Stats,一种发现你的应用管理内存的服务,在Dianne Hackborn的博客文章Process Stats: Understanding How Your App Uses RAM中有所解释:
Android Studio 0.8.10引入了一个名为Memory Monitor的非常有用的工具 .
它有什么好处:
图1.在Android Memory Monitor上强制执行GC(垃圾收集)事件
通过使用它,您可以获得有关应用程序RAM实时消耗的大量信息 .
1)我猜不是,至少不是来自Java .
2)
我们发现获取当前进程总内存的所有标准方法都存在一些问题 .
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)最后,我们最终使用以下代码:
它返回 VmRSS metric . 您可以在此处找到有关它的更多详细信息:one,two和three .
P.S. 我注意到如果性能不是关键要求,主题仍然缺乏如何估计进程的私有内存使用情况的实际和简单的代码片段:
上面有很多答案肯定对你有所帮助,但是(经过两天的adb内存工具研究和支持)我想我也可以帮助我 opinion .
因为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.所以你无法获得每个进程的确切内存量 .
但是你可以通过一些逻辑来接近它......我将告诉你如何......
首先,您需要成为root用户才能使其正常工作 . 通过在进程中执行
su
进入具有root权限的控制台并获取其output and input stream
. 然后在ouputstream中传递id\n
(输入)并将其写入过程输出,如果将获得输入流包含uid=0
, you are root user.现在,这是您将在上述过程中使用的逻辑
当您获得进程 pass you command (procrank, dumpsys meminfo etc...) with \n instead of id 的ouputstream并获取其
inputstream
并读取时,将该流存储在bytes [],char []等中..使用 raw data..and您已完成!!!!!许可:
检查您是否是root用户:
使用
su
执行命令logcat:
这只是一个尝试,如果我错过了什么,请建议我