Android 内存之监控篇

一、前言

内存问题主要会造成如下几个影响。第一、会发生OOM等异常,因为每个对象都会占用一定的内存,内存过多会影响对象的分配失败,严重者会导致设备重启。第二、内存过大,导致系统回收缓存内存,以及会加快GC频率,从而导致应用卡顿。

内存的监控就尤为的重要。下面从几个方面来看Android对内存的监控,从而有助于观察内存变化。

二、free

free是轻量级的查看设备整体内存情况,具体例子如下:

root@debian7:/proc/10# free
             total       used       free     shared    buffers     cached
Mem:       3044840     247692    2797148          0      19896     110084
-/+ buffers/cache:     117712    2927128
Swap:       901116          0     901116

其中total = used + free,单位KB。
对于-/+ buffers/cache行,是从有无缓冲来看。117712 = used - buffers - cached.
2927128 = free + buffers + cached.

三、/proc/meminfo文件

/proc/meminfo是free的加强版,free中的数据也是从/proc/meminfo而来的。

root@debian7:/proc/10# cat /proc/meminfo
MemTotal:        3044840 kB  // RAM内存总大小
MemFree:         2797520 kB  // RAM可用内存大小
Buffers:           19912 kB  // Buffers缓存,文件缓存
Cached:           110084 kB  // Cached缓存大小
SwapCached:            0 kB
Active:            97184 kB // 在活跃下的缓冲或高速缓冲存储器页面文件的大小
Inactive:          94008 kB // 非活跃下的缓冲或高速缓冲存储器页面文件的大小
Active(anon):      61312 kB // Active = Active(anon) + Active(file)
Inactive(anon):     6008 kB
Active(file):      35872 kB
Inactive(file):    88000 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:        901116 kB
SwapFree:         901116 kB
Dirty:                 0 kB // 等待被写回到磁盘的内存大小。
Writeback:             0 kB // 正在被写回到磁盘的内存大小。
AnonPages:         61188 kB
Mapped:            24656 kB // 文件通过mmap分配的内存
Shmem:              6132 kB
Slab:              20412 kB //  内核数据结构缓存的大小。Linux中的Slab内存分配策略,相对于伙伴系统分配
SReclaimable:       6288 kB
SUnreclaim:        14124 kB
KernelStack:        1000 kB
PageTables:         4656 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     2423536 kB
Committed_AS:     535828 kB
VmallocTotal:   34359738367 kB  // 总分配的虚拟地址空间
VmallocUsed:      158760 kB  // 已分配的虚拟地址空间
VmallocChunk:   34359576572 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:       45056 kB
DirectMap2M:     2076672 kB
DirectMap1G:     1048576 kB

四、vmstat

vmstat命令可以查看内存、IO和CPU等信息。

语法命令:

Usage: vmstat [ -n iterations ] [ -d delay ] [ -r header_repeat ]
    -n iterations     数据循环输出的次数
    -d delay          两次数据间的延迟时长(单位:S)
    -r header_repeat  循环多少次,再输出一次头信息行

vmstat例子:

root@debian7:/proc/10# vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 0  0      0 2797396  19960 110084    0    0     1     0   13   25  0  0 100  0

procs 程序

  • r : 运行的进程数量
  • b :等待IO阻塞的进程数量

memory 内存

  • swpd : 虚拟内存(swap空间)已使用的大小
  • free :剩余的物理内存大小
  • buff : buff缓存大小
  • cache :文件等cache大小

swap swap空间,内存够用时,si和so值都为0

  • si : swap空间写入内存的数据量;
  • so: 内存写入swap空间的数据量;

IO

  • bi : 每秒从块设备读取块的数量
  • bo:每秒向块设备写入的块数量

system

  • in : 每秒的中断次数
  • cs :等秒的上下文切换次数

cpu

  • us : 用户态执行时间
  • sy : 内核态执行时间
  • id : 空闲时间(包括IO等待时间)
  • wa : 等待IO时间

五、/proc/[PID]/status

root@p212:/data/dropbear # cat /proc/4943/status
Name:   XXXXX
State:  S (sleeping) : 状态
Tgid:   4943 :线程组ID
Pid:    4943 :进程ID,同TGID,说明是主线程
PPid:   3769 :父进程ID
TracerPid:      0
Uid:    10039   10039   10039   10039
Gid:    10039   10039   10039   10039
Ngid:   0
FDSize: 64 :FDSize是当前分配过的文件描述符数量
Groups: 3003 9997 50039 : groups表示启动这个进程的用户所在的组.
VmPeak:  1503968 kB :当前进程运行过程中占用内存的峰值
VmSize:   878224 kB  :虚拟内存大小
VmLck:         0 kB
VmPin:         0 kB
VmHWM:     40040 kB :分配到物理内存的峰值
VmRSS:     38120 kB : 虚拟内存驻留集合大小
VmData:   134084 kB :进程数据段的大小
VmStk:      8196 kB : 进程堆栈段的大小
VmExe:        20 kB
VmLib:     69224 kB
VmPTE:       440 kB
VmSwap:        0 kB : 进程占用Swap的大小.
Threads:        22 :线程数量
SigQ:   0/2462
SigPnd: 0000000000000000 : 存储了该线程的待处理信号
ShdPnd: 0000000000000000 : 存储了该线程组的待处理信号
SigBlk: 0000000000001204 : 存放被阻塞的信号
SigIgn: 0000000000000000 : 存放可被忽略的信号
SigCgt: 00000002000094f8
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000000000000000
Seccomp:        0
Cpus_allowed:   f
Cpus_allowed_list:      0-3
voluntary_ctxt_switches:        358 : 进程主动切换上下文的次数(资源得不到等)
nonvoluntary_ctxt_switches:     400 : 进程被动切换上下文的次数.

六、Android#Runtime

Android中提供了一些接口,供使用者调用,可定时的采集以下几种内存情况,从而判断当前进程内存情况。

        Runtime runtime = Runtime.getRuntime();
        long javaMax = runtime.maxMemory();  //  JVM可分配的最大内存
        long javaTotal = runtime.totalMemory();  //  当前分配的内存
        long javaUsed = javaTotal - runtime.freeMemory();  //  当前使用的内存
        
        float proportion = (float) javaUsed / javaMax;
        Log.e("TAG", "onResume: javaMax="+javaMax+";javaTotal="+javaTotal+";javaUsed="+javaUsed+";proportion="+proportion);

七、Android#onLowMemory

在Android4.0中提供了一些监听内存的接口OnLowMemory和onTrimMemory

【一】、OnLowMemory

OnLowMemory是ComponentCallbacks接口中的方法,当系统内存不足,要被杀死后台程序时,会调用该方法。

可用在Application、Activity、Fragement、Service和ContentProvider中

【二】、onTrimMemory

因为OnLowMemory的接口太简单了,并没有提供内存的状态,在ComponentCallbacks2中丰富了回调了接口。

public interface ComponentCallbacks2 extends ComponentCallbacks {

    /** @hide */
    @IntDef(prefix = { "TRIM_MEMORY_" }, value = {
            TRIM_MEMORY_COMPLETE,
            TRIM_MEMORY_MODERATE,
            TRIM_MEMORY_BACKGROUND,
            TRIM_MEMORY_UI_HIDDEN,
            TRIM_MEMORY_RUNNING_CRITICAL,
            TRIM_MEMORY_RUNNING_LOW,
            TRIM_MEMORY_RUNNING_MODERATE,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface TrimMemoryLevel {}

    static final int TRIM_MEMORY_COMPLETE = 80;
    
    static final int TRIM_MEMORY_MODERATE = 60;
   
    static final int TRIM_MEMORY_BACKGROUND = 40;
    
    static final int TRIM_MEMORY_UI_HIDDEN = 20;

    static final int TRIM_MEMORY_RUNNING_CRITICAL = 15;

    static final int TRIM_MEMORY_RUNNING_LOW = 10;

    static final int TRIM_MEMORY_RUNNING_MODERATE = 5;

    void onTrimMemory(@TrimMemoryLevel int level);
}

同onLowMemory一致,也可用在Application、Activity、Fragement、Service和ContentProvider中。

  • TRIM_MEMORY_COMPLETE:内存不足,并且该进程在后台进程列表最后一个,马上就要被清理
  • TRIM_MEMORY_MODERATE:内存不足,并且该进程在后台进程列表的中部。
  • TRIM_MEMORY_BACKGROUND:内存不足,并且该进程是后台进程。
  • TRIM_MEMORY_UI_HIDDEN:内存不足,并且该进程的UI已经不可见了。
  • TRIM_MEMORY_RUNNING_CRITICAL:内存不足,并且该进程不是消耗性的后台进程,需要清理内存
  • TRIM_MEMORY_RUNNING_LOW:内存不足,并且该进程不是消耗性的后台进程,需要清理内存
  • TRIM_MEMORY_RUNNING_MODERATE:内存不足,并且该进程不是消耗性的后台进程,需要清理内存

八、dumpsys

通过adb shell dumpsys meminfo [pid | 包名] 可以查看单个APP内存情况

如下:

Applications Memory Usage (kB):
Uptime: 31564143 Realtime: 31564143

** MEMINFO in pid 30712 [XXX] **
                   Pss  Private  Private  Swapped     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     2196     2092        0        0     6144     4855     1288
  Dalvik Heap     1517     1396        0        0     3873     2449     1424
 Dalvik Other      373      372        0        0
        Stack      132      132        0        0
       Ashmem        2        0        0        0
    Other dev        5        0        4        0
     .so mmap     1148       96      156        0
    .apk mmap      326        0       28        0
    .ttf mmap       88        0       76        0
    .dex mmap     2844        4     2840        0
    .oat mmap     1204        0      164        0
    .art mmap     1321      476      368        0
   Other mmap       11        8        0        0
    GL mtrack     2960     2960        0        0
      Unknown      121      120        0        0
        TOTAL    14248     7656     3636        0    10017     7304     2712

 App Summary
                       Pss(KB)
                        ------
           Java Heap:     2240
         Native Heap:     2092
                Code:     3364
               Stack:      132
            Graphics:     2960
       Private Other:      504
              System:     2956

               TOTAL:    14248      TOTAL SWAP (KB):        0

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

 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

第一部分主要字段解析:
  • Native Heap : Native堆大小
  • Dalvik Heap : java堆大小
  • Stack :栈大小
  • Ashmem : 匿名共享内存大小
  • .so mmap : 映射的so库大小
  • .apk mmap:apk占用内存大小
  • .dex mmap : dex占用内存大小
  • Pss Total :物理内存总大小
  • Private Dirty : 进程私有的内存,相对磁盘数据有改动的内存
  • Private Clean : 进程私有的内存,相对磁盘数据没有修改的内存
  • Heap Size : Dalvik中,同runtime.totalMemory()
  • Heap Alloc : Dalvik中,同runtime.totalMemory()-runtime.freeMemory()
  • Heap Free : Dalvik中,同runtime.freeMemory()
App Summary主要字段解析:
  • Java Heap : Dalvik Heap 中的 Private Dirty + .art mmap 的 Private Dirty + Private Clean
  • Native Heap :Native Heap
  • Code : .so mmap+ .jar mmap + .apk mmap + .ttf mmap + .dex mmap + .oat mmap的 Private Dirty + Private Clean
  • Stack :Stack
Objects主要字段解析:
  • Views :存活的view的个数
  • ViewRootImpl : 存活的ViewRootImpl数量
  • AppContexts :APP整个上下文数量
  • Activities : 存活的Activity数量
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343