[小笔记] 如何解读 dumpsys meminfo 的信息

4,420 阅读7分钟

[小笔记] 如何解读 dumpsys meminfo 的信息

通过 adb 命令 adb shell dumpsys meminfo [pakcage name] 能够很简单的看到对应应用的内存使用总体情况,这里面的信息我自己也很容易忘记,我也在网上查找过许多的资料,我发现很多都是写得乱七八糟的,所以我决定自己针对官方的文档和 StackOverflow 中的优秀回答来记录一下。

这是我的应用使用上述命令后展示的信息(不同的 Android 版本,展示的信息可能有区别):

Applications Memory Usage (in Kilobytes):
Uptime: 76374295 Realtime: 369954849

** MEMINFO in pid 15901 [com.phx.waha.dev] **
                   Pss  Private  Private  SwapPss      Rss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------
  Native Heap    77711    77684        0       23    79112   105984    88719    17264
  Dalvik Heap    13888    13788        0       77    15364    17353     8677     8676
 Dalvik Other     3702     2980        0        0     5416                           
        Stack     1908     1908        0        0     1920                           
       Ashmem       55       12        0        0      504                           
    Other dev       48        0       44        0      632                           
     .so mmap    43724     2460    35820       15    79656                           
    .jar mmap     6071        0     3344        0    37364                           
    .apk mmap      698        0      232        0     2288                           
    .ttf mmap     1047        0      264        0     2640                           
    .dex mmap    12702      512    12180        0    13428                           
    .oat mmap       52        0        4        0     1744                           
    .art mmap     8602     7948       92       43    19540                           
   Other mmap      112       40       64        0      908                           
    GL mtrack    67368    67368        0        0    67368                           
      Unknown     1277     1256        8        0     1688                           
        TOTAL   239123   175956    52052      158   329572   123337    97396    25940
 
 App Summary
                       Pss(KB)                        Rss(KB)
                        ------                         ------
           Java Heap:    21828                          34904
         Native Heap:    77684                          79112
                Code:    54836                         138068
               Stack:     1908                           1920
            Graphics:    67368                          67368
       Private Other:     4384
              System:    11115
             Unknown:                                    8200
 
           TOTAL PSS:   239123            TOTAL RSS:   329572       TOTAL SWAP PSS:      158
 
 Objects
               Views:       53         ViewRootImpl:        2
         AppContexts:        7           Activities:        2
              Assets:       28        AssetManagers:        0
       Local Binders:       31        Proxy Binders:       63
       Parcel memory:       14         Parcel count:       55
    Death Recipients:        3      OpenSSL Sockets:        0
            WebViews:        0
 
 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

我主要分析 MEMINFO 中的横坐标和纵坐标表示意思(有的我也不知道什么意思😂,我就列举下我知道的),其他的部分都很好理解我就不说了。

列

Pss Total

它的全称是 Proportional Set Size。首先我们要知道我们的应用中内存中的数据可以分为共享的和私有的。比如说系统中所有进程都能够用的资源文件就属于共享的(Shared);我们自己应用的分配的内存,别的应用无法读取的就是私有的(Private)。PSS 就是用来统计内存占用的一种方式,PSS = 私有内存占用 + 共享内存占用 / 共享进程数,通常我们也都使用 PSS 来表示总体的内存占用;还有一种统计内存占用的方式就是 RSS,RSS = 私有内存占用 + 共享内存占用,通常我们不会用 RSS 来表示总体的内存占用,只是做一个参考。

Private Dirty / Clean

Private 的内存占用仅供我们自己的进程使用,当进程销毁时系统可以回收 Private 中的绝大部分内存 (我不清楚为什么不是全部🤔),通常最重要的部分就是 Private Dirty 部分,我们应用请求分配的内存也都是这部分,它的占用也是最大的,Android 系统中默认不支持 Linux Swap 机制,它不能保存到磁盘上。所有的 Dalvik 虚拟机和 native 分配的堆内存都是 Private Dirty 的。
官方的文档没有明确表示什么样的内存是 Dirty 的,什么样的内存是 Clean 的,我在 StackOverflow 中看到有人回答了这个问题。

Private Dirty

这部分内存用于我们计算,内存中的内容也是可以修改的,我们自己写的代码分配的内存都是这部分内存。他们也不会被 Swap,当我们的进程被销毁后,这部分内存会被全部回收。

Private Clean

这部分内存从磁盘加载到内存中后就不会修改,比如我们的 dex 字节码和 native 机器码,后续的 .dex mmap 和 .so mmap 行中的内容就能够很容易看到这一点。
从 Zygote 进程 fork() 后没有修改的数据也是 Clean 的,如果被修改了就会变成 Dirty。

SwapPss Dirty

Android 官方文档也没有对这部分内存解释,以下解释都来自 StackOverflow。

前面说到 Android 默认不支持 Linux 的 Swap 机制,这个 Swap 机制是指 Swap 到本地磁盘存储。不懂 Swap 可以看看我之前写的文章:聊聊虚拟内存。这里是类似于 Linux 中的 ZRAM 机制,当内存不足时会把一部分内存压缩交换到 Compressed Page 中,以便节省内存,当需要这部分内存时再把他解压后重新加载到对应的 Page 中。

Rss Total

前面讲 PSS 的时候有讲到,只是一种统计内存的方式:RSS = 私有内存占用 + 共享内存占用。

Heap Size

堆的大小。

Heap Alloc

已经分配的堆的大小。

Heap Free

空余的堆大小,计算方式为 Heap Free = Heap Size - Heap Alloc。

行

Native Heap

Native 分配的堆内存占用大小,这里有一个让人很费解的点,为什么 Heap Alloc 占用的内存要大于 PSS 呢?是因为这部分内存包含 Zygote fork() 前的共享数据,所以比 PSS 要大,但是为什么比 RSS 还大我就不知道原因了,官方没有讲,可能是他们的计算方式不一样。

Dalvik Heap

Dalvik 虚拟机堆内存占用大小,其他的都是和 Native Heap 类似的。

Dalvik Other

主要是 Dalvik 虚拟机的 JIT 和 GC 占用的内存。

Stack

方法栈占用内存。

.so mmap

native 机器码所占内存,我们能够看到大部分的占用是 private clean 的,也就是不修改的私有内存。

.dex mmap / .jar mmap

dex 字节码占用内存和 jar 字节码占用内存,和 .so mmap 类似。

.ttf mmap

字体文件占用内存,感兴趣的可以去了解了解 FreeType。

.oat mmap

framework 中的代码镜像,供所有的其他进程共享,例如我们使用的 Activity 的代码就在其中。所以我们能够看到 PSS 很小,但是 RSS 很大。

.art mmap

和 .oat mmap 类似,是 ART 虚拟机的代码镜像。

GL mtrack

Open GL 图像相关占用内存,和后面的 Graphics 对应。

还有一些其他的参数就不说了,有的都比较简单,非常直白,有的我也没有搞懂,你可以自己再去查查。

总结

通常我们看内存分析也只是看关键的几个信息,我们先从列来开始看:PSS,Private Dirty,Heap Size,Heap Alloc 和 Heap Free。从行来看:Native Heap,Dalvik Heap 和 GL mtrack。主要通过以上指标我们就能知道内存大体的占用情况,其他指标也可以参考一下,如果想要看 Heap 中具体的内存占用,还需要借助别的工具,比如说 Android Studio 中的 Profiler。

参考文章

官方文档

StackOverflow