如何以编程方式找到我的 Android 应用程序上使用的内存?
我希望有办法做到这一点。另外,我如何获得手机的免费内存?
原文由 Andrea Baccega 发布,翻译遵循 CC BY-SA 4.0 许可协议
如何以编程方式找到我的 Android 应用程序上使用的内存?
我希望有办法做到这一点。另外,我如何获得手机的免费内存?
原文由 Andrea Baccega 发布,翻译遵循 CC BY-SA 4.0 许可协议
是的,您可以通过编程方式获取内存信息并决定是否进行内存密集型工作。
通过调用获取 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 获取源代码
原文由 coocood 发布,翻译遵循 CC BY-SA 3.0 许可协议
15 回答8.4k 阅读
8 回答6.2k 阅读
1 回答4k 阅读✓ 已解决
3 回答6k 阅读
3 回答2.2k 阅读✓ 已解决
2 回答3.1k 阅读
2 回答3.8k 阅读
请注意,现代操作系统(如 Linux)上的内存使用是一个 极其 复杂且难以理解的领域。事实上,你真正正确地解释你得到的任何数字的机会是极低的。 (几乎每次我与其他工程师一起查看内存使用数据时,总是会就它们的实际含义进行长时间的讨论,结果只会得出一个模糊的结论。)
注意:我们现在有更多关于 管理您的应用程序内存的 文档,其中涵盖了此处的大部分材料,并且与 Android 的状态保持同步。
第一件事可能是阅读本文的最后一部分,其中讨论了如何在 Android 上管理内存:
服务 API 从 Android 2.0 开始发生变化
现在
ActivityManager.getMemoryInfo()
是我们查看整体内存使用情况的最高级别 API。这主要是为了帮助应用程序衡量系统离后台进程没有更多内存有多近,因此需要开始终止所需的进程,如服务。对于纯 Java 应用程序,这应该没什么用,因为 Java 堆限制部分是为了避免一个应用程序能够对系统施加压力到这一点。在较低级别,您可以使用调试 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
可能是更准确的……但实际上,这只留下了重点:“对你获得的任何内存信息持保留态度;通常是非常大的一粒盐。”最后是命令
adb shell cat /proc/meminfo
给出了系统总体内存使用情况的摘要。这里有很多数据,值得讨论的只有前几个数字(其余的很少有人理解,而且我对那几个人的问题经常导致相互矛盾的解释):MemTotal
是内核和用户空间可用的内存总量(通常小于设备的实际物理 RAM,因为无线电、DMA 缓冲区等需要一些 RAM)。MemFree
是根本没有使用的内存量。你在这里看到的数字非常高;通常在 Android 系统上这将只有几 MB,因为我们尝试使用可用内存来保持进程运行Cached
是用于文件系统缓存和其他类似事物的 RAM。典型的系统需要有 20MB 左右的空间来避免进入错误的分页状态; Android 内存不足杀手针对特定系统进行了调整,以确保后台进程在缓存 RAM 被消耗过多以导致此类分页之前被杀死。