内存监控

单独分析某一时刻的内存情况可以排查潜在的内存不合理使用,除此之外,我们也需要关注App运行期间内存的整体变化,比如在自动化测试期间定期获取内存数据,通过整合一段时间内的内存数据,形成一个曲线报表;再比如将每个版本的的内存曲线作对比,可以直观的了解某一个版本是否出现了内存使用激增。

procstats获取进程内存信息

如何获取内存的快照呢?

根据Android SDK的提供的工具,我们一般可以用adb配套的命令工具来获取,比如说获取一段时间内整个内存的使用报告,可以用procstats

aven-mac-pro-2:platform-tools aven$ adb shell dumpsys procstats --hours 1

那么procstats支持什么参数?--hours 1肯定代表的是一个小时的范围。其实这些参数很多,不需要记忆,使用的使用直接查看帮助文档就好了。

一般命令行的帮助命令都是-h或者--help之类的:

aven-mac-pro-2:platform-tools aven$  adb shell dumpsys procstats -h
Process stats (procstats) dump options:
    [--checkin|-c|--csv] [--csv-screen] [--csv-proc] [--csv-mem]
    [--details] [--full-details] [--current] [--hours N] [--last N]
    [--max N] --active] [--commit] [--reset] [--clear] [--write] [-h]
    [--start-testing] [--stop-testing] 
    [--pretend-screen-on] [--pretend-screen-off] [--stop-pretend-screen]
    [<package.name>]
  --checkin: perform a checkin: print and delete old committed states.
  -c: print only state in checkin format.
  --csv: output data suitable for putting in a spreadsheet.
  --csv-screen: on, off.
  --csv-mem: norm, mod, low, crit.
  --csv-proc: pers, top, fore, vis, precept, backup,
    service, home, prev, cached
  --details: dump per-package details, not just summary.
  --full-details: dump all timing and active state details.
  --current: only dump current state.
  --hours: aggregate over about N last hours.
  --last: only show the last committed stats at index N (starting at 1).
  --max: for -a, max num of historical batches to print.
  --active: only show currently active processes/services.
  --commit: commit current stats to disk and reset to start new stats.
  --reset: reset current stats, without committing.
  --clear: clear all stats; does both --reset and deletes old stats.
  --write: write current in-memory stats to disk.
  --read: replace current stats with last-written stats.
  --start-testing: clear all stats and starting high frequency pss sampling.
  --stop-testing: stop high frequency pss sampling.
  --pretend-screen-on: pretend screen is on.
  --pretend-screen-off: pretend screen is off.
  --stop-pretend-screen: forget "pretend screen" and use the real state.
  -a: print everything.
  -h: print this help text.
  <package.name>: optional name of package to filter output by.
``

默认procstats打印出所所有进程的信息,对我们来说,可能有点多,毕竟我们一般就是想看看待测应用的数据,这个时候可以跟上应用的包名,再加上`-a`打出所有信息:

```shell
aven-mac-pro-2:platform-tools aven$ adb shell dumpsys procstats --hours 3 -a cn.hacktons.leakdemo
AGGREGATED OVER LAST 3 HOURS:
Per-Package Stats:
  * cn.hacktons.leakdemo / u0a86 / v1:
      Process cn.hacktons.leakdemo (unique, 1 entries):
        SOn /Norm/Top    : +3h33m17s952ms
                  TOTAL  : +3h33m17s952ms
        PSS/USS (1 entries):
          SOn /Norm/Top    : 49287 samples 13MB 29MB 42MB / 9.1MB 23MB 38MB
        myID=257eab6 mCommonProcess=257eab6 mPackage=cn.hacktons.leakdemo

  Total procs: 0 shown of 26 total

Summary:
  * cn.hacktons.leakdemo / u0a86 / v1:
           TOTAL: 81% (13MB-29MB-42MB/9.1MB-23MB-38MB over 49287)
             Top: 81% (13MB-29MB-42MB/9.1MB-23MB-38MB over 49287)

Run time Stats:
  SOn /Norm: +4h22m13s88ms
      TOTAL: +4h22m13s88ms

Memory usage:
  Persist: 157MB (54 samples)
  Top    : 38MB (49328 samples)
  ImpFg  : 91MB (91 samples)
  ImpBg  : 89MB (128 samples)
  Service: 23MB (82 samples)
  Receivr: 6.8KB (51 samples)
  LastAct: 12MB (46 samples)
  CchAct : 63MB (9 samples)
  CchEmty: 75MB (118 samples)
  TOTAL  : 547MB
  ServRst: 70 (13 samples)

          Start time: 2018-03-26 07:13:00
  Total elapsed time: +4h22m13s92ms (partial) (swapped-out-pss) libart.so

Internal state:
  mRunning=false

Available pages by page size:
Zone   0       Unmovable      2     1     2     0     0     0     0     0     0     0     0
Zone   0     Reclaimable      3     0     4     7     6     5     4     1     0     0     0
Zone   0         Movable      1     0     1     0     1     1     1     0     0     0     0
Zone   0         Reserve      0     0     0     0     0     0     0     0     0     0     0
Zone   0             CMA      0     0     0     0     0     0     0     0     0     0     0
Zone   0         Isolate      0     0     0     0     0     0     0     0     0     0     0
Zone   0       Unmovable    142   352   261    51    12     0     0     0     0     0     0
Zone   0     Reclaimable     18    18    24    17     0     0     0     0     0     0     0
Zone   0         Movable    100  2635  2270   854   295    55     5     0     0     0     0
Zone   0         Reserve      0     0     0     0     0     0     0     0     0     0     1
Zone   0             CMA    839   838   837   625   682   412   189    41     5     2     5
Zone   0         Isolate      0     0     0     0     0     0     0     0     0     0     0
Zone   0       Unmovable     39    50    17     5     5     2     1     2     0     2     1
Zone   0     Reclaimable      0     0     0     0     0     0     0     0     0     0     0
Zone   0         Movable     55   119   896   394   139    60    45    26    10     0     1
Zone   0         Reserve      0     0     0     0     0     0     0     0     0     0     1
Zone   0             CMA      0     0     0     0     0     0     0     0     0     0     0
Zone   0         Isolate      0     0     0     0     0     0     0     0     0     0     0

meminfo获取内存快照

除了获取一个时间段内的进程的粗略信息,我们也可以通过meminfo来获取指定进程的内存快照。

aven-mac-pro-2:Desktop aven$ adb shell dumpsys meminfo cn.hacktons.leakdemo
Applications Memory Usage (in Kilobytes):
Uptime: 88948299 Realtime: 88948299

** MEMINFO in pid 12049 [cn.hacktons.leakdemo] **
                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     4102     3840        0        0    13824    12187     1636
  Dalvik Heap      550      516        0        0     9355     4678     4677
 Dalvik Other      392      392        0        0                           
        Stack      228      228        0        0                           
       Ashmem        5        0        0        0                           
    Other dev       10        0        8        0                           
     .so mmap     1423      196        0        0                           
    .apk mmap      396        0        0        0                           
    .ttf mmap       45        0        0        0                           
    .dex mmap     3709        4     2316        0                           
    .oat mmap      285        0        0        0                           
    .art mmap     3914     3668        0        0                           
   Other mmap       13        4        0        0                           
      Unknown      355      328        0        0                           
        TOTAL    15427     9176     2324        0    23179    16865     6313

 App Summary
                       Pss(KB)
                        ------
           Java Heap:     4184
         Native Heap:     3840
                Code:     2516
               Stack:      228
            Graphics:        0
       Private Other:      732
              System:     3927

               TOTAL:    15427       TOTAL SWAP PSS:        0

 Objects
               Views:       17         ViewRootImpl:        1
         AppContexts:        3           Activities:        1
              Assets:        2        AssetManagers:        3
       Local Binders:        9        Proxy Binders:       16
       Parcel memory:        3         Parcel count:       12
    Death Recipients:        0      OpenSSL Sockets:        0
            WebViews:        0

 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

上面的输出更加细致,区分了App中的Native Heap,Dalvik Heap等。

定时采集内存数据就可以利用meminfo来处理。他所支持的参数也可以通过-h输出:

aven-mac-pro-2:Desktop aven$ adb shell dumpsys meminfo -h
meminfo dump options: [-a] [-d] [-c] [-s] [--oom] [process]
  -a: include all available information for each process.
  -d: include dalvik details.
  -c: dump in a compact machine-parseable representation.
  -s: dump only summary of application memory usage.
  -S: dump also SwapPss.
  --oom: only show processes organized by oom adj.
  --local: only collect details locally, don't call process.
  --package: interpret process arg as package, dumping all
             processes that have loaded that package.
  --checkin: dump data for a checkin
If [process] is specified it can be the name or 
pid of a specific process to dump.

数据的理解

现在我们已经知道如何获取大量的数据,如何读懂这些数据也是个问题。我们可以通过对比系统设置中的可视化页面来推测含义,也可以分析源代码,注释来理解不同输出的含义。

相关源代码:com.android.internal.app.ProcessStats.java

这些工作读者可以可好自己去完成。下面我们简单看下这段常见输出的含义:

TOTAL: 81% (13MB-29MB-42MB/9.1MB-23MB-38MB over 49287)

As can be seen in the example below, the output displays what percentage of time the application was running, and the PSS and USS as minPSS-avgPSS-maxPSS/minUSS-avgUSS-maxUSS over the number of samples.

这一行日志的含义大致是:在我们观察的指定时间段内,该进程运行时间占了81%,数据采采样总计49287次,PSS和USS的情况是13MB-29MB-42MB/9.1MB-23MB-38MB

关于PSS和USS的概念,可以简单了解下,一般在linux中经常见到,特别是输出系统信息的时候。

  • PSS: proportional set size的缩写,代表一个进程所使用的内存总和,包括独占的私有内存和进程间共享的内存
  • USS: unique set size的缩写,代表一个进程所使用的独占内存,和上面的PSS的差异就在于不包含共享内存

举个例子来说:

某一时刻,进程cn.hacktons.leakdemo的非共享内存大小为23MB,进程cn.android.system的非共享内存为50MB, cn.hacktons.leakdemo和cn.android.system共享内存大小是12MB,那我们可以简单得出以下PSS数据:

  • cn.hacktons.leakdemo PSS = 23MB + 12/2MB = 29MB
  • cn.android.system PSS = 50MB + 12/2MB = 56MB

当然这里对共享内存简单二等分的做法也并不是锁一定共享使用的只有1/2,这是计算使用量时的一个简单处理方法而已。

监控报表

通过脚本或者开发程序定时获取内存信息,我们可以得到一组内存数据,利用可视化的图表,比如曲线图将采样的数据实时或者非实时展现出来,就实现了我们需要的监控图表;

参考

powered by Gitbook更新: 2018-04-16

results matching ""

    No results matching ""