性能优化工具(十)- Android内存分析命令

一、内存指标
Item 全称 含义 等价
USS Unique Set Size 物理内存 进程独占的内存
PSS Proportional Set Size 物理内存 PSS= USS+ 按比例包含共享库
RSS Resident Set Size 物理内存 RSS= USS+ 包含共享库
VSS Virtual Set Size 虚拟内存 VSS= RSS+ 未分配实际物理内存

内存的大小关系:VSS >= RSS >= PSS >= USS

二、常用内存分析命令

1 procrank

获取所有进程的内存使用的排行榜,排行是以Pss的大小而排序,能输出详细的VSS/RSS/PSS/USS内存指标。

  PID       Vss      Rss      Pss      Uss     Swap    PSwap    USwap    ZSwap  cmdline

 1479  2748552K  382328K  224152K  168908K   26040K   16185K   15944K    3575K  system_server

   ...

                          1817679K  1618480K  1530116K  470311K  433840K  103909K  TOTAL

ZRAM: 111212K physical used for 503364K in swap (1048572K total swap)

RAM: 2914764K total, 41284K free, 11904K buffers, 592500K cached, 11672K shmem, 183752K slab

2 free

查看可用内存,缺省单位KB。该命令比较简单、轻量,专注于查看剩余内存情况。数据来源于/proc/meminfo。

total        used        free      shared     buffers

Mem:       2984718336  2946801664    37916672    11943936    11337728

-/+ buffers/cache:     2935463936    49254400

Swap:      1073737728   515416064   558321664  

对于Mem行,存在的公式关系: total = used + free;
对于-/+ buffers行:buffers/cache used = mem used - mem buffers
buffers/cache free = mem free + mem buffers

3 cat /proc/meminfo

展示的是系统整体内存情况,内存项按类型进行分类:

MemTotal:        2914764 kB  内存总数 (除去BIOS和内核预留的内存,剩下可供系统支配的内存)
MemFree:           78008 kB 系统空闲内存(系统尚未被使用的,total-free = used)
MemAvailable:     440972 kB 可用内存(memfree + 可回收内存(部分buffer/cached,slab也能回收一部分))
Buffers:           14200 kB 缓冲区内存(给文件做缓冲的)
Cached:           566648 kB 缓存区内存(被高速缓冲存储器(cache memory)用的内存)
SwapCached:        60560 kB 缓存区中已经被交换出来的内存
Active:          1243832 kB 在活跃使用中的缓冲或高速缓冲存储器页面文件的大小,除非非常必要否则不会被移作他用
Inactive:         576108 kB 在不经常使用中的缓冲或高速缓冲存储器页面文件的大小,可能被用于其他途径
Active(anon):    1043860 kB
Inactive(anon):   377368 kB
Active(file):     199972 kB
Inactive(file):   198740 kB
Unevictable:      173940 kB
Mlocked:          173940 kB 被系统锁定的页面
SwapTotal:       1048572 kB 交换空间的总大小(设置的zram交换空间大小)
SwapFree:         471124 kB 未被使用交换空间的大小
Dirty:                72 kB 等待被写回到磁盘的内存大小
Writeback:             0 kB 正在被写回到磁盘的内存大小
AnonPages:       1407356 kB 未映射页的内存大小
Mapped:           435656 kB 已经被设备和文件等映射的内存大小
Shmem:              8388 kB 共享内存大小
Slab:             176044 kB 内核中slab分配的内存大小(slab = SReclaimable+SUnreclaim)
SReclaimable:      55528 kB 可收回Slab的内存大小
SUnreclaim:       120516 kB 不可收回Slab的内存大小
KernelStack:       56144 kB 内核栈区大小
PageTables:        61256 kB 内存管理的分页的页表大小
NFS_Unstable:          0 kB 不稳定页表的大小
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     2505952 kB
Committed_AS:   95946620 kB
VmallocTotal:  258998208 kB 可以被vmalloc分配的虚拟内存大小
VmallocUsed:      142860 kB 已经被使用的虚拟内存大小
VmallocChunk:  258740196 kB

日常使用经验总结:

1)MemTotal: 是除去系统底层预留内存之外,能被系统使用的总内存大小,正常情况下会比实际内存小一点,但是如果小太多的话属于预留不合理,需要看看原因,这属于先天不足,天花板过低。

2)MemFree 、MemAvailable: 前者是当前系统未被使用的内存,后者是当前系统可以被使用的内存(包括可以被回收的部分内存),意思就那个什么,挤挤还是有的。从经验上来说,如果当前MemAvailable底于总内存的1/10,那么系统可能会出现因为内存造成的卡顿,其中原因可能包括频繁回收内存造成的阻塞、耗时以及寻址难度加大变相地增加了内存分配的时间等等。

3)Buffers 、Cached: 前者用于缓存磁盘blocks以优化block I/O,后者用于缓存文件内容以优化文件I/O。部分内存是可被回收的,被算到MemAvailable中。MemAvailable ≈ MemFree+Buffers+Cached。

4)Mlocked: 被系统锁定的页面。比如系统中google 7.0加的PinnerService 就会有这个效果,把常用的内容锁定在内存中,避免频繁的内存回收与分配,优化但不限于提升io效率。典型的用空间换时间,如果是Android 2G及其以下内存的手机,建议关闭PinnerService,要啥自行车。PinnerService官方描述

5)SwapTotal、SwapFree: 这就zram,如果为0就是没打开。SwapTotal是zram总空间大小,SwapFree是没交换的空间大小。

6)Slab: 内核基于Buddy做了page的粗分,Slab基于Buddy做了内存二次划分,这部分就是基于Slab内存分配的内存大小。使用的函数是kmalloc/kfree。 SReclaimable和SUnreclaim分别是Slab的可回收和不可回收部分(slab = SReclaimable+SUnreclaim),如果Slab比较大,可能是kernel debug开关被打开了(也不一定,具体看调试内容),而且SUnreclaim也非常大的话,可能存在kernel泄漏。

7)Kernel内存可使用内存 ≈ Slab + KernelStack + PageTables。

4 dumpsys meminfo

4.1 dumpsys实现逻辑简单介绍

dumpsys的源码结构其实很简单,只有一个dumpsys.cpp
源码路径是:/frameworks/native/cmds/dumpsys/dumpsys.cpp

在其main方法中,先通过defaultServiceManager()函数获得ServiceManager对象,然后根据dumpsys传进来的参数通过函数checkService来找到具体的service, 并执行该service的dump方法,达到dump service的目的。

4.2 dumpsys meminfo 数据组成

dumpsys meminfo对应的服务是:ActivityManagerService, 它从memBinder类的dump函数开始执行的。

static class MemBinder extends Binder {
   ActivityManagerService mActivityManagerService;
   MemBinder(ActivityManagerService activityManagerService) {
       mActivityManagerService = activityManagerService;
   }

   @Override

   protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
       if (mActivityManagerService.checkCallingPermission(android.Manifest.permission.DUMP)
               != PackageManager.PERMISSION_GRANTED) {
           pw.println("Permission Denial: can't dump meminfo from from pid="
                   + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
                   + " without permission " + android.Manifest.permission.DUMP);
           return;
       }
       mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, "  ", args, false, null);
   }
}

主要收集内存信息并打印是在dumpApplicationMemoryUsage方法中做的,但是该方法比较大,就不列出来了,举个例子:

Debug.getMemoryInfo(pid, mi);//通过debug.java中的getMemoryInfo函数来获取当前进程的整体memory信息,获取的是对应的/proc/$<pid>/smaps文件统计出来的信息。getMemoryInfo是个native方法,对应到android_os_Debug.cpp的android_os_Debug_getDirtyPagesPid。

从代码看:这部分内容是从/proc/$<pid>/smaps获取的。

那么总结下dumpsys meminfo的出处:

很明显,dumpsys meminfo 获取的数据是从系统各个渠道汇集来的。

4.3 dumpsys meminfo 展示的是系统整体内存情况, 内存项按进程进行分类

Total PSS by process:         Java层存活的进程及其占用内存情况
    241,086K: system (pid 1479)
    161,423K: surfaceflinger (pid 544)
    137,754K: com.android.systemui (pid 4843 / activities)
    ...
Total PSS by OOM adjustment:  Native存活的进程及其占用内存情况
    376,783K: Native
        161,423K: surfaceflinger (pid 544)
         14,303K: audioserver (pid 725)
          9,247K: zygote (pid 719)
    ...
    576,007K: Persistent      按进程优先级分别来统计对应的进程及其内存使用情况, 列举几个:
        241,086K: system (pid 1479)
    ...
    219,381K: Foreground
        167,657K: com.tengxin.youqianji (pid 29421 / activities)
    ...
    317,970K: B Services
         33,115K: com.UCMobile:channel (pid 25225)
    ...
    410,541K: Cached
         36,294K: com.android.vending (pid 13418)
    ...

Total PSS by category: 按类型进行分类
    555,972K: Dalvik
    401,562K: Native
    154,436K: EGL mtrack
    151,504K: Unknown
    145,638K: .oat mmap
    118,919K: .dex mmap
    118,259K: .art mmap
     88,952K: GL mtrack
     73,583K: Dalvik Other
     51,418K: Gfx dev
     39,993K: .so mmap
     28,950K: .apk mmap
     27,075K: Stack
      9,919K: Ashmem
      6,219K: Other mmap
      1,968K: Other dev
        120K: .jar mmap
         80K: .ttf mmap
         16K: Cursor
          0K: Other mtrack

Total RAM: 2,914,764K (status normal)
 Free RAM: 1,208,341K (  410,541K cached pss +   730,784K cached kernel +     2,676K cached ion +    64,340K free)
 Used RAM: 2,326,986K (1,994,786K used pss +   332,200K kernel)
 Lost RAM:   -16,504K
     ZRAM:   101,812K physical used for   466,040K in swap (1,048,572K total swap)
   Tuning: 192 (large 512), oom   322,560K, restore limit   107,520K (high-end-gfx)

先总结下最下面的统计:

Total RAM:内存总数,与proc/meminfo中的MemTotal一致。
Free RAM:cached pss + cached kernel + cached ion + free 手机剩余内存一般是看它

  • cached pss:dumpsys meminfo中 cached 进程的PSS总和
  • cached kernel:这个暂时无定论
  • free:proc/meminfo 的MemFree
  • ion cached以及gpu cached:display相关ion的内存占用

Used RAM:used pss+kernel+trace buffer+ion display+cma usage

  • used pss:native process PSS+dumpsys meminfo APP除cached部分的PSS总和
  • kernel:meminfo的Shmem+Slab+PageTables+kernelStack+vmallocinfo里面的ioremap项+map_lowmem项所占内存的和
  • ion disp:display相关的ion模块内存占用
  • cma usage:cma模块占用

Lost RAM:与cache ion有关

ZRAM:zram swap转换情况

Tuning:这一行主要是system的一些设置,没看过

5 dumpsys meminfo [pid | packageName]

查看单个进程内存详情

** MEMINFO in pid 1479 [system] **
                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap    26106    25984      104     8739    73728    34267    39460
  Dalvik Heap    63706    63676        4     1858    56528    40144    16384
 Dalvik Other     6704     6668       12       24                          
        Stack     2388     2364       24     1352                          
       Ashmem     8004     8000        0        0                          
      Gfx dev      532      124        0        0                          
    Other dev       55        8       36        0                          
     .so mmap     1561      444      780      488                          
    .jar mmap        0        0        0        8                          
    .apk mmap      145        0        0        0                          
    .dex mmap    28702        0     4428       40                          
    .oat mmap    78494        0    49992        0                          
    .art mmap     3068     2684       76      856                          
   Other mmap       34        4        0        0                          
    GL mtrack     1424     1424        0        0                          
      Unknown     1275     1084      188     2882                          
        TOTAL   238445   112464    55644    16247   130256    74411    55844
 App Summary
                       Pss(KB)
                        ------
           Java Heap:    66436
         Native Heap:    25984
                Code:    55644
               Stack:     2364
            Graphics:     1548
       Private Other:    16132
              System:    70337
               TOTAL:   238445       TOTAL SWAP PSS:    16247
 Objects
               Views:        3         ViewRootImpl:        1
         AppContexts:       20           Activities:        0
              Assets:        8        AssetManagers:        6
       Local Binders:      888        Proxy Binders:     1652
       Parcel memory:     1697         Parcel count:      751
    Death Recipients:      753      OpenSSL Sockets:        0

数据来源:

纵轴:

属性名 说明
Native Heap 在 Native Code 中使用 malloc 分配出的内存
Dalvik Heap Dalvik 虚拟机分配的空间,不包括它自身的开销。Dalvik 堆中和 Zygote 进程共享的部分算是 sharedDirty
Dalvik Other 类数据结构和索引占据的内存
Stack 栈内存
Cursor CursorWindow 占用的空间,与 SQL 有关
Ashmem 匿名共享内存,此类内存与 cache shrinker 关联,可以控制cache shrinker在适当时机回收这些共享内存
Gfx dev /dev/kgsl-3d0 占用的内存
Other dev 内部driver占用的内存
.so mmap 映射的 .so(native)代码占用的内存
.jar mmap Java 文件代码占用内存
.apk mmap apk 代码占用内存
.ttf mmap ttf 文件代码占用内存
.dex mmap 映射的 .dex(Dalvik 或 ART)代码占用的内存
.oat mmap 代码映像占用的 RAM 量。此映像在所有应用之间共享,不受特定应用影响
.art mmap 堆映像占用的 RAM 量。此映像在所有应用之间共享,不受特定应用影响。尽管 ART 映像包含 Object 实例,它仍然不会计入您的堆大小
Other mmap 其它文件占用的内存

横轴:

属性名 说明
Pss Total 实际使用的内存,这里考虑了与 Zygote 的共享。任何独占的内存页直接计算它的PSS值,而和其它进程共享的页则按照共享的比例计算PSS值
Private Dirty 进程私有的,相对磁盘数据有改动的内存
Private Clean 进程私有的,相对磁盘数据没有修改的内存
SwapPss Dirty Android 4.4 的一个优化,swap to zRAM。牺牲CPU,减少内存。这两个值的区别在于内核是否是统计按比例分出的swap数据,是的输出为 SwapPss Dirty。
Swap Dirty Whether the kernel reports proportional swap usage

Heap相关:

Heap Size Heap Alloc Heap Free
Native Heap 从mallinfo usmblks获得,代表最大总共分配空间 从mallinfo uorblks获得,总共已分配空间 从mallinfo fordblks获得,代表总共剩余空间
Dalvik Heap 从Runtime totalMemory()获得,Dalvik Heap总共的内存大小 Runtime totalMemory()-freeMemory() ,Dalvik Heap分配的内存大小 从Runtime freeMemory()获得,Dalvik Heap剩余的内存大小

App Summary:

属性名 内存组成
Java Heap Dalvik Heap 的 Private Dirty
.art mmap 的 Private Dirty + Private Clean
Native Heap Native Heap 的 Private Dirty
Code .so mmap
.jar mmap
.apk mmap
.ttf mmap
.dex mmap
.oat mmap的 Private Dirty + Private Clean
Stack Stack 的 Private Dirty
Graphics Gfx dev
EGL mtrack
GL mtrack的 Private Dirty + Private Clean
Private Other Native Heap
Dalvik Heap
- HEAP_UNKNOWN的 Private Dirty + Private Clean
System Native Heap
Dalvik Heap
HEAP_UNKNOWN的 Pss + SwapPss Dirty - Private Dirty - Private Clean
TOTAL Native Heap
Dalvik Heap
HEAP_UNKNOWN的 Pss + SwapPss Dirty
TOTAL SWAP PSS Native Heap
Dalvik Heap
HEAP_UNKNOWN的 SwapPss Dirty
TOTAL SWAP (KB) Native HEAP
Dalvik Heap
HEAP_UNKNOWN的 Swap Dirty

Object:


这里通常会通过看Activities、AppContexts来判断是否有内存泄漏,比如刚退出应用,查看Object中Activities是否为0,如果不为0,则有Activity没有销毁,很有可能存在泄漏。

参考:
https://www.cnblogs.com/adv-qbj/p/4719787.html
https://www.jianshu.com/p/9e47b1cce077
https://blog.csdn.net/zsj100213/article/details/78572383
https://blog.csdn.net/manok/article/details/82896288

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容