一尘不染

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

java android

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

我希望有一种方法可以做到。另外,我也该如何获得手机的空闲内存?


阅读 282

收藏
2020-02-25

共1个答案

一尘不染

请注意,现代操作系统(如Linux)上的内存使用是一个极其复杂且难以理解的领域。实际上,你正确解释任何数字的机会非常低。(几乎每当我与其他工程师一起查看内存使用量数字时,对于它们的实际含义总会进行长时间的讨论,这只会导致模糊的结论。)

注意:我们现在有更多有关管理应用程序内存的文档,其中涵盖了许多内容,并且是有关Android状态的最新信息。

第一件事可能是阅读本文的最后部分,该部分讨论了如何在Android上管理内存:

从Android 2.0开始更改服务API

现在ActivityManager.getMemoryInfo()是我们用于查看整体内存使用情况的最高级别的API。这主要是为了帮助应用程序评估系统将如何接近没有更多内存供后台进程使用,因此需要开始杀死所需的进程(如服务)。对于纯Java应用程序,这应该没有多大用处,因为Java堆限制在某种程度上避免了一个应用程序能够使系统承受这一压力。

进入较低级别,你可以使用Debug API获得有关内存使用情况的原始内核级别信息:android.os.Debug.MemoryInfo

请注意,从2.0开始,还有一个API ActivityManager.getProcessMemoryInfo来获取有关另一个进程的此信息:ActivityManager.getProcessMemoryInfo(int [])

这将返回具有所有以下数据的低级MemoryInfo结构:

    /** 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,现在好了。PrivateDirtySharedDirty

实际上,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给我系统进程:

** 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

顶部是主要部分,其中size是特定堆的地址空间中的总大小,allocated是堆认为具有的实际分配的kb,free是堆可用于其他分配的剩余kb,并且pss与priv dirty相同如前所述,专门针对与每个堆相关的页面。

如果只想查看所有进程的内存使用情况,则可以使用命令adb shell procrank。在同一系统上的输出如下所示:

  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 24308s 24com google.google.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 / 
   installed 60 396K 392K 93K 84K / system / bin / keystore
   51 280K 276K 74K 68K / system / bin / servicemanager 
   54 256K 252K 69K 64K / system / bin / debuggerd

这里的VssRss列基本上是噪音(这些是进程的直接地址空间和RAM使用情况,如果你将各个进程之间的RAM使用情况相加,则会得到非常高的数字)。

Pss正如我们之前所见,并且UssPriv Dirty

在此需要注意的有趣事情:PssUss我们在中看到的内容略有不同(或略有不同)meminfo。这是为什么?好procrank使用的内核机制与收集数据的机制不同meminfo,它们给出的结果略有不同。这是为什么?老实说我没头绪。我相信procrank可能是更准确的……但是,实际上,这就是要说的:“获取一粒盐得到的任何存储信息;通常是非常大的一粒。”

最后,该命令adb shell cat /proc/meminfo提供了系统整体内存使用情况的摘要。这里有很多数据,只有前几个值得讨论(剩下的几个人很少理解,而我对这几个人的问题经常会引起相互矛盾的解释):

MemTotal:         395144 kB
MemFree:          184936 kB
Buffers:             880 kB
Cached:            84104 kB
SwapCached:            0 kB

MemTotal 是内核和用户空间可用的内存总量(通常少于设备的实际物理RAM,因为无线电,DMA缓冲区等需要一些RAM)。

MemFree 是根本不使用的RAM数量。你在这里看到的数字很高;通常在Android系统上只有几MB,因为我们尝试使用可用内存来保持进程运行

Cached 是用于文件系统缓存和其他此类事物的RAM。典型的系统将需要大约20MB的内存,以避免陷入不良的分页状态。针对特定系统对Android内存不足杀手进行了调整,以确保在后台进程被缓存RAM占用过多而导致这种分页之前,后台进程被杀死。

2020-02-25