1 内存指标概念
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
2 内存分析命令
常用的内存调优分析命令:
- dumpsys meminfo
- cat /proc/meminfo
- procrank
- free
- showmap
- vmstat
2.1 dumpsys meminfo
Applications Memory Usage (in Kilobytes):
Uptime: 56803948 Realtime: 328348979
Total PSS by process://以process来划分,按照进程的PSS的大小来由大到小进行排列
172,452K: system (pid 957)
168,257K: com.android.systemui (pid 1309 / activities)
89,061K: com.emoji.keyboard.touchpal (pid 1304)
86,228K: com.facebook.katana (pid 2903)
67,818K: surfaceflinger (pid 360)
…………………
Total PSS by OOM adjustment://以OOM的类别来进行划分Native/System/Persistent/Foreground/Visible/Perceptible/A Services/Home/B Services/Cached,分别显示每类的进程情况
1,254,482K: Native
67,818K: surfaceflinger (pid 360)
59,100K: cameraserver (pid 490)
30,774K: zygote (pid 487)
20,646K: zygote64 (pid 486)
………………
172,452K: System
172,452K: system (pid 957)
420,974K: Persistent
168,257K: com.android.systemui (pid 1309 / activities)
64,637K: com.android.gallery3d (pid 2062)
40,031K: com.mediatek.camera (pid 1591)
………………
121,299K: Foreground
17,787K: android.process.acore (pid 18435)
146,745K: Visible
51,754K: com.google.android.gms.persistent (pid 2101)
48,103K: com.google.android.gms (pid 2367)
………………
89,061K: Perceptible
89,061K: com.emoji.keyboard.touchpal (pid 1304)
24,594K: A Services
………………
31,628K: B Services
17,720K: android.process.media (pid 2074)
………………
203,989K: Cached
86,228K: com.facebook.katana (pid 2903)
45,959K: com.google.android.googlequicksearchbox:search (pid 27390)
………………
Total PSS by category://以category进行划分,以Dalvik/Native/.art mmap/.dex map等划分的各类进程的总PSS情况
598,588K: .dex mmap
424,583K: .apk mmap
359,730K: .so mmap
315,668K: Dalvik
……………………
Total RAM: 5,958,380K (status moderate)
Free RAM: 3,312,193K ( 203,989K cached pss + 1,369,648K cached kernel + 1,320,228K free + 108,784K ion cached + 309,544K gpu cached)
Used RAM: 2,635,803K (2,261,235K used pss + 356,284K kernel + 56K trace buffer + 18,228K ion disp + 0K cma usage)
Lost RAM: 10,380K
ZRAM: 4K physical used for 0K in swap (2,979,188K total swap)
Tuning: 192 (large 384), oom 322,560K, restore limit 107,520K (high-end-gfx)
重点说的是total部分的内容,搜索网上的资料没有找到特别有用的内容,只能自己查看code,这里面有些值可以透过读取proc/meminfo的节点获取,有些事透过其他的节点获取(在activitymanageservice.java中),透过readMemInfo()和readExtraMemInfo()函数来获取。
Total RAM: 5,958,380K (status moderate)//系统总共的可用内存。
Free RAM: 3,312,193K ( 203,989K cached pss + 1,369,648K cached kernel + 1,320,228K free + 108,784K ion cached + 309,544K gpu cached)
//cached pss指上层app cache所占的memory大小。
Used RAM: 2,635,803K (2,261,235K used pss + 356,284K kernel + 56K trace buffer + 18,228K ion disp + 0K cma usage)
//used pss指上层app所占用的不可回收的内存大小,它等于APP所占的总的内存大小减去cached pss的大小。
Lost RAM: 10,380K
这个我理解为kernel申请的由driver使用的内存,kernel不会计算这部分内存,所以称为lost ram。
2.2 cat /proc/meminfo
MemTotal: 2857.032 kB //RAM可用的总大小 (即物理总内存减去系统预留和内核二进制代码大小)
MemFree: 1020.708 kB //RAM未使用的大小
Buffers: 75.104 kB //用于块设备访问的缓冲
Cached: 448.244 kB //用于高速缓存
SwapCached: 0 kB //用于swap缓存
Active: 832.900 kB //活跃使用状态,记录最近使用过的内存,通常不回收用于其它目的
Inactive: 391.128 kB //非活跃使用状态,记录最近并没有使用过的内存,能够被回收用于其他目的
Active(anon): 700.744 kB //Active = Active(anon) + Active(file)
Inactive(anon): 228 kB //Inactive = Inactive(anon) + Inactive(file)
Active(file): 132.156 kB
Inactive(file): 390.900 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 524.284 kB //swap总大小
SwapFree: 524.284 kB //swap可用大小
Dirty: 0 kB //等待往磁盘回写的大小
Writeback: 0 kB //正在往磁盘回写的大小
AnonPages: 700.700 kB
Mapped: 187.096 kB //通过mmap()分配的内存,用于map设备、文件或者库
Shmem: .312 kB
Slab: 91.276 kB //kernel数据结构的缓存大小,Slab=SReclaimable+SUnreclaim
SReclaimable: 32.484 kB //可回收的slab的大小
SUnreclaim: 58.792 kB //不可回收slab的大小
KernelStack: 25.024 kB
PageTables: 23.752 kB //以最低的页表级
NFS_Unstable: 0 kB //不稳定页表的大小
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 1952.800 kB
Committed_AS: 82204.348 kB //评估完成的工作量,代表最糟糕case下的值,该值也包含swap内存
VmallocTotal: 251658.176 kB //总分配的虚拟地址空间
VmallocUsed: 166.648 kB //已使用的虚拟地址空间
VmallocChunk: 251398.700 kB //虚拟地址空间可用的最大连续内存块
内存都到哪里去了?
使用内存的,不是kernel就是用户进程,下面我们就分类讨论。
注:page cache比较特殊,很难区分是属于kernel还是属于进程,其中被进程mmap的页面自然是属于进程的了,而另一些页面没有被mapped到任何进程,那就只能算是属于kernel了。
内核
内核所用内存的静态部分,比如内核代码、页描述符等数据在引导阶段就分配掉了,并不计入MemTotal里,而是算作Reserved(在dmesg中能看到)。而内核所用内存的动态部分,是通过上文提到的几个接口申请的,其中通过alloc_pages申请的内存有可能未纳入统计,就像黑洞一样。
下面讨论的都是/proc/meminfo中所统计的部分。
- SReclaimable: slab中可回收的部分。调用kmem_getpages()时加上SLAB_RECLAIM_ACCOUNT标记,表明是可回收的,计入SReclaimable,否则计入SUnreclaim。
- SUnreclaim: slab中不可回收的部分。
- Slab: slab中所有的内存,等于以上两者之和。
VmallocUsed
通过vmalloc分配的内存都统计在/proc/meminfo的 VmallocUsed 值中,但是要注意这个值不止包括了分配的物理内存,还统计了VM_IOREMAP、VM_MAP等操作的值,譬如VM_IOREMAP是把IO地址映射到内核空间、并未消耗物理内存,所以我们要把它们排除在外。从物理内存分配的角度,我们只关心VM_ALLOC操作,这可以从/proc/vmallocinfo中的vmalloc记录看到:
# grep vmalloc /proc/vmallocinfo
...
0xffffc90004702000-0xffffc9000470b000 36864 alloc_large_system_hash+0x171/0x239 pages=8 vmalloc N0=8
0xffffc9000470b000-0xffffc90004710000 20480 agp_add_bridge+0x2aa/0x440 pages=4 vmalloc N0=4
0xffffc90004710000-0xffffc90004731000 135168 raw_init+0x41/0x141 pages=32 vmalloc N0=32
0xffffc90004736000-0xffffc9000473f000 36864 drm_ht_create+0x55/0x80 [drm] pages=8 vmalloc N0=8
0xffffc90004744000-0xffffc90004746000 8192 dm_table_create+0x9e/0x130 [dm_mod] pages=1 vmalloc N0=1
0xffffc90004746000-0xffffc90004748000 8192 dm_table_create+0x9e/0x130 [dm_mod] pages=1 vmalloc N0=1
...
注:/proc/vmallocinfo中能看到vmalloc来自哪个调用者(caller),那是vmalloc()记录下来的,相应的源代码可见:
mm/vmalloc.c: vmalloc > __vmalloc_node_flags > __vmalloc_node > __vmalloc_node_range > __get_vm_area_node > setup_vmalloc_vm
一些driver以及网络模块和文件系统模块可能会调用vmalloc,加载内核模块(kernel module)时也会用到,可参见 kernel/module.c。
kernel modules (内核模块)
系统已经加载的内核模块可以用 lsmod 命令查看,注意第二列就是内核模块所占内存的大小,通过它可以统计内核模块所占用的内存大小,但这并不准,因为”lsmod”列出的是[init_size+core_size],而实际给kernel module分配的内存是以page为单位的,不足 1 page的部分也会得到整个page,此外每个module还会分到一页额外的guard page。
# lsmod | less
Module Size Used by
rpcsec_gss_krb5 31477 0
auth_rpcgss 59343 1 rpcsec_gss_krb5
nfsv4 474429 0
dns_resolver 13140 1 nfsv4
nfs 246411 1 nfsv4
lockd 93977 1 nfs
sunrpc 295293 5 nfs,rpcsec_gss_krb5,auth_rpcgss,lockd,nfsv4
fscache 57813 2 nfs,nfsv4
lsmod的信息来自/proc/modules,它显示的size包括init_size和core_size,相应的源代码参见:
1
2
3
4
5
6
7
8
|
|
注:我们可以在 /sys/module/<module-name>/ 目录下分别看到coresize和initsize的值。
kernel module的内存是通过vmalloc()分配的(参见下列源代码),所以在/proc/vmallocinfo中会有记录,也就是说我们可以不必通过”lsmod”命令来统计kernel module所占的内存大小,通过/proc/vmallocinfo就行了,而且还比lsmod更准确,为什么这么说呢?
// kernel/module.c
static int move_module(struct module *mod, struct load_info *info)
{
...
ptr = module_alloc_update_bounds(mod->core_size);
...
if (mod->init_size) {
ptr = module_alloc_update_bounds(mod->init_size);
...
}
// 注:module_alloc_update_bounds()最终会调用vmalloc_exec()
因为给kernel module分配内存是以page为单位的,不足 1 page的部分也会得到整个page,此外,每个module还会分到一页额外的guard page。
详见:mm/vmalloc.c: __get_vm_area_node()
而”lsmod”列出的是[init_size+core_size],比实际分配给kernel module的内存小。我们做个实验来说明:
# 先卸载floppy模块
$ modprobe -r floppy
# 确认floppy模块已经不在了
$ lsmod | grep floppy
# 记录vmallocinfo以供随后比较
$ cat /proc/vmallocinfo > vmallocinfo.1
# 加载floppy模块
$ modprobe -a floppy
# 注意floppy模块的大小是69417字节:
$ lsmod | grep floppy
floppy 69417 0
$ cat /proc/vmallocinfo > vmallocinfo.2
# 然而,我们看到vmallocinfo中记录的是分配了73728字节:
$ diff vmallocinfo.1 vmallocinfo.2
68a69
> 0xffffffffa03d7000-0xffffffffa03e9000 73728 module_alloc_update_bounds+0x14/0x70 pages=17 vmalloc N0=17
# 为什么lsmod看到的内存大小与vmallocinfo不同呢?
# 因为给kernel module分配内存是以page为单位的,而且外加一个guard page
# 我们来验证一下:
$ bc -q
69417%4096
3881 <--- 不能被4096整除
69417/4096
16 <--- 相当于16 pages,加上面的3881字节,会分配17 pages
18*4096 <--- 17 pages 加上 1个guard page
73728 <--- 正好是vmallocinfo记录的大小
所以结论是kernel module所占用的内存包含在/proc/vmallocinfo的统计之中,不必再去计算”lsmod”的结果了,而且”lsmod”也不准。
HardwareCorrupted
当系统检测到内存的硬件故障时,会把有问题的页面删除掉,不再使用,/proc/meminfo中的HardwareCorrupted统计了删除掉的内存页的总大小。相应的代码参见 mm/memory-failure.c: memory_failure()
PageTables
Page Table用于将内存的虚拟地址翻译成物理地址,随着内存地址分配得越来越多,Page Table会增大,/proc/meminfo中的PageTables统计了Page Table所占用的内存大小。
注:请把Page Table与Page Frame(页帧)区分开,物理内存的最小单位是page frame,每个物理页对应一个描述符(struct page),在内核的引导阶段就会分配好、保存在mem_map[]数组中,mem_map[]所占用的内存被统计在dmesg显示的reserved中,/proc/meminfo的MemTotal是不包含它们的。(在NUMA系统上可能会有多个mem_map数组,在node_data中或mem_section中)。
而Page Table的用途是翻译虚拟地址和物理地址,它是会动态变化的,要从MemTotal中消耗内存。
KernelStack
每一个用户线程都会分配一个kernel stack(内核栈),内核栈虽然属于线程,但用户态的代码不能访问,只有通过系统调用(syscall)、自陷(trap)或异常(exception)进入内核态的时候才会用到,也就是说内核栈是给kernel code使用的。在x86系统上Linux的内核栈大小是固定的8K或16K。
Kernel stack(内核栈)是常驻内存的,既不包括在LRU lists里,也不包括在进程的RSS/PSS内存里,所以我们认为它是kernel消耗的内存。统计值是/proc/meminfo的KernelStack。
Buffers
Buffers统计的是直接访问块设备时的缓冲区的总大小,有时候对文件系统元数据的操作也会用到buffers。这部分内存不好直接对应到某个用户进程,应该算作kernel占用。
Bounce
有些老设备只能访问低端内存,比如16M以下的内存,当应用程序发出一个I/O 请求,DMA的目的地址却是高端内存时(比如在16M以上),内核将在低端内存中分配一个临时buffer作为跳转,把位于高端内存的缓存数据复制到此处。这种额外的数据拷贝被称为“bounce buffering”,会降低I/O 性能。大量分配的bounce buffers 也会占用额外的内存。
用户进程
/proc/meminfo统计的是系统全局的内存使用状况,单个进程的情况要看/proc/<pid>/下的smaps等等。
Shmem
/proc/meminfo中的Shmem统计的内容包括:
- shared memory
- tmpfs。
AnonPages
用户进程的内存页分为两种:file-backed pages(与文件对应的内存页),和anonymous pages(匿名页)。Anonymous pages(匿名页)的数量统计在/proc/meminfo的AnonPages中。
以下是几个事实,有助于了解Anonymous Pages:
- 所有page cache里的页面(Cached)都是file-backed pages,不是Anonymous Pages。
注:shared memory 不属于 AnonPages,而是属于Cached,因为shared memory基于tmpfs,所以被视为file-backed、在page cache里,上一节解释过。 - mmap private anonymous pages属于AnonPages(Anonymous Pages),而mmap shared anonymous pages属于Cached(file-backed pages),因为shared anonymous mmap也是基于tmpfs的
- Anonymous Pages是与用户进程共存的,一旦进程退出,则Anonymous pages也释放,不像page cache即使文件与进程不关联了还可以缓存。
- AnonPages统计值中包含了Transparent HugePages (THP)对应的 AnonHugePages
Mapped
上面提到的用户进程的file-backed pages就对应着/proc/meminfo中的”Mapped”。Page cache中(“Cached”)包含了文件的缓存页,其中有些文件当前已不在使用,page cache仍然可能保留着它们的缓存页面;而另一些文件正被用户进程关联,比如shared libraries、可执行程序的文件、mmap的文件等,这些文件的缓存页就称为mapped。
/proc/meminfo中的”Mapped”就统计了page cache(“Cached”)中所有的mapped页面。
因为Linux系统上shared memory & tmpfs被计入page cache(“Cached”),所以被attached的shared memory、以及tmpfs上被map的文件都算做”Mapped”。
进程所占的内存页分为anonymous pages和file-backed pages,理论上应该有:
【所有进程的PSS之和】 == 【Mapped + AnonPages】。
然而实际测试的结果,虽然两者很接近,却总是无法精确相等,我猜也许是因为进程始终在变化、采集的/proc/[1-9]*/smaps以及/proc/meminfo其实不是来自同一个时间点的缘故。
Cached
Page Cache里包括所有file-backed pages,统计在/proc/meminfo的”Cached”中。
- Cached不仅包括mapped,也包括unmapped的页面,当一个文件不再与进程关联之后,原来在page cache中的页面并不会立即回收,仍然被计入Cached,还留在LRU中,但是 Mapped 统计值会减小。【ummaped = (Cached – Mapped)】
- Cached包含tmpfs中的文件,POSIX/SysV shared memory,以及shared anonymous mmap。
注:POSIX/SysV shared memory和shared anonymous mmap在内核中都是基于tmpfs实现的
有意思的是,Shared memory和tmpfs在不发生swap-out的时候属于”Cached”,而在swap-out/swap-in的过程中会被加进swap cache中、属于”SwapCached”,一旦进了”SwapCached”,就不再属于”Cached”了。”Cached”和”SwapCached”两个统计值是互不重叠的
SwapCached
我们说过,匿名页(anonymous pages)要用到交换区,而shared memory和tmpfs虽然未统计在AnonPages里,但它们背后没有硬盘文件,所以也是需要交换区的。也就是说需要用到交换区的内存包括:”AnonPages”和”Shmem”,我们姑且把它们统称为匿名页好了。
交换区可以包括一个或多个交换区设备(裸盘、逻辑卷、文件都可以充当交换区设备),每一个交换区设备都对应自己的swap cache,可以把swap cache理解为交换区设备的”page cache”:page cache对应的是一个个文件,swap cache对应的是一个个交换区设备,kernel管理swap cache与管理page cache一样,用的都是radix-tree,唯一的区别是:page cache与文件的对应关系在打开文件时就确定了,而一个匿名页只有在即将被swap-out的时候才决定它会被放到哪一个交换区设备,即匿名页与swap cache的对应关系在即将被swap-out时才确立。
并不是每一个匿名页都在swap cache中,只有以下情形之一的匿名页才在:
- 匿名页即将被swap-out时会先被放进swap cache,但通常只存在很短暂的时间,因为紧接着在pageout完成之后它就会从swap cache中删除,毕竟swap-out的目的就是为了腾出空闲内存;
【注:参见mm/vmscan.c: shrink_page_list(),它调用的add_to_swap()会把swap cache页面标记成dirty,然后它调用try_to_unmap()将页面对应的page table mapping都删除,再调用pageout()回写dirty page,最后try_to_free_swap()会把该页从swap cache中删除。】 - 曾经被swap-out现在又被swap-in的匿名页会在swap cache中,直到页面中的内容发生变化、或者原来用过的交换区空间被回收为止。
【注:当匿名页的内容发生变化时会删除对应的swap cache,代码参见mm/swapfile.c: reuse_swap_page()。】
/proc/meminfo中的SwapCached背后的含义是:系统中有多少匿名页曾经被swap-out、现在又被swap-in并且swap-in之后页面中的内容一直没发生变化。也就是说,如果这些匿名页需要被swap-out的话,是无需进行I/O write操作的。
“SwapCached”不属于”Cached”,两者没有交叉。Mlocked
“Mlocked”统计的是被mlock()系统调用锁定的内存大小。被锁定的内存因为不能pageout/swapout,会从Active/Inactive LRU list移到Unevictable LRU list上。也就是说,当”Mlocked”增加时,”Unevictable”也同步增加,而”Active”或”Inactive”同时减小;当”Mlocked”减小的时候,”Unevictable”也同步减小,而”Active”或”Inactive”同时增加。
“Mlocked”并不是独立的内存空间,它与以下统计项重叠:LRU Unevictable,AnonPages,Shmem,Mapped等。
内存黑洞
追踪Linux系统的内存使用一直是个难题,很多人试着把能想到的各种内存消耗都加在一起,kernel text、kernel modules、buffer、cache、slab、page table、process RSS…等等,却总是与物理内存的大小对不上,这是为什么呢?因为Linux kernel并没有滴水不漏地统计所有的内存分配,kernel动态分配的内存中就有一部分没有计入/proc/meminfo中。
我们知道,Kernel的动态内存分配通过以下几种接口:
- alloc_pages/__get_free_page: 以页为单位分配
- vmalloc: 以字节为单位分配虚拟地址连续的内存块
- slab allocator
- kmalloc: 以字节为单位分配物理地址连续的内存块,它是以slab为基础的,使用slab层的general caches — 大小为2^n,名称是kmalloc-32、kmalloc-64等(在老kernel上的名称是size-32、size-64等)。
通过slab层分配的内存会被精确统计,可以参见/proc/meminfo中的slab/SReclaimable/SUnreclaim;
通过vmalloc分配的内存也有统计,参见/proc/meminfo中的VmallocUsed 和 /proc/vmallocinfo(下节中还有详述);
而通过alloc_pages分配的内存不会自动统计,除非调用alloc_pages的内核模块或驱动程序主动进行统计,否则我们只能看到free memory减少了,但从/proc/meminfo中看不出它们具体用到哪里去了。比如在VMware guest上有一个常见问题,就是VMWare ESX宿主机会通过guest上的Balloon driver(vmware_balloon module)占用guest的内存,有时占用得太多会导致guest无内存可用,这时去检查guest的/proc/meminfo只看见MemFree很少、但看不出内存的去向,原因就是Balloon driver通过alloc_pages分配内存,没有在/proc/meminfo中留下统计值,所以很难追踪。
kernel内存的统计方式应该比较明确,即
【Slab+ VmallocUsed + PageTables + KernelStack + Buffers + HardwareCorrupted + Bounce + X】
用户进程的内存主要有三种统计口径:
- [1]围绕LRU进行统计
【(Active + Inactive + Unevictable) + (HugePages_Total * Hugepagesize)】 - [2]围绕Page Cache进行统计
当SwapCached为0的时候,用户进程的内存总计如下:
【(Cached + AnonPages) + (HugePages_Total * Hugepagesize)】
当SwapCached不为0的时候,以上公式不成立,因为SwapCached可能会含有Shmem,而Shmem本来被含在Cached中,一旦swap-out就从Cached转移到了SwapCached,可是我们又不能把SwapCached加进上述公式中,因为SwapCached虽然不与Cached重叠却与AnonPages有重叠,它既可能含有Shared memory又可能含有Anonymous Pages。 - [3]围绕RSS/PSS进行统计
把/proc/[1-9]*/smaps 中的 Pss 累加起来就是所有用户进程占用的内存,但是还没有包括Page Cache中unmapped部分、以及HugePages,所以公式如下:
ΣPss + (Cached – mapped) + (HugePages_Total * Hugepagesize)
所以系统内存的使用情况可以用以下公式表示:
- MemTotal = MemFree +【Slab+ VmallocUsed + PageTables + KernelStack + Buffers + HardwareCorrupted + Bounce + X】+【Active + Inactive + Unevictable + (HugePages_Total * Hugepagesize)】
- MemTotal = MemFree +【Slab+ VmallocUsed + PageTables + KernelStack + Buffers + HardwareCorrupted + Bounce + X】+【Cached + AnonPages + (HugePages_Total * Hugepagesize)】
- MemTotal = MemFree +【Slab+ VmallocUsed + PageTables + KernelStack + Buffers + HardwareCorrupted + Bounce + X】+【ΣPss + (Cached – mapped) + (HugePages_Total * Hugepagesize)】
2.3 procrank
Android procrank (/system/xbin/procrank) 工具,能够列出进程所占用的内存使用情况,顺序为从高到低。Usage: procrank [ -W ] [ -v | -r | -p | -u | -h ]
02. -v Sort by VSS.
03. -r Sort by RSS.
04. -p Sort by PSS.
05. -u Sort by USS.
06. (Default sort order is PSS.)
07. -R Reverse sort order (default is descending).
08. -w Display statistics for working set only.
09. -W Reset working set of all processes.
10. -h Display this help screen.
执行结果
1|root@android:/ # procrank
02.procrank
03. PID Vss Rss Pss Uss cmdline
04. 1780 48188K 36892K 21177K 18196K system_server
05. 1953 44944K 36056K 17201K 14904K com.android.systemui
06. 2109 51300K 34888K 15291K 12840K com.android.launcher
07. 2248 32996K 32948K 14184K 12516K com.tencent.qqpimsecure
08. 2913 29880K 29796K 11980K 9612K android.process.acore
09. 1396 36280K 36168K 11762K 7552K zygote
10. 2058 27200K 27132K 10204K 9120K com.android.phone
11. 2352 26028K 25960K 9680K 8740K com.wandoujia.phoenix2
12. 2670 25388K 25312K 8064K 6332K com.sina.weibo
13. 2029 22276K 22204K 6700K 6040K android.process.media
14. 2866 23504K 23428K 6161K 4424K com.sina.weibo.servant
15. 2632 21700K 21624K 6071K 5384K com.infinit.wostore.ui
16. 1398 8904K 8904K 5948K 5012K /system/bin/mediaserver
17. 2484 21580K 21508K 5679K 4892K com.android.email
18. 2704 20512K 20436K 5601K 4936K com.tmall.wireless:core
19. 2399 20384K 20300K 4990K 4248K com.android.contacts
20. 2746 20720K 20660K 4973K 4188K com.android.browser
21. 2090 20376K 20320K 4805K 4084K com.android.nfc
22. 2043 20516K 20448K 4753K 4012K com.android.inputmethod.pinyin
23. 2200 20272K 20196K 4679K 3868K com.android.settings
24. 2563 20028K 19952K 4492K 3640K com.android.mms
25. 2788 19304K 19232K 4123K 3396K com.android.calendar
26. 2436 19812K 19744K 4119K 3520K com.android.providers.calendar
27. 2505 18724K 18648K 3973K 3460K com.android.exchange
28. 2655 19588K 19516K 3972K 3320K com.android.dazhihui
29. 2465 19816K 19736K 3894K 3160K com.android.deskclock
30. 2233 18756K 18684K 3467K 2824K com.android.music
31. 2605 17540K 17460K 2824K 2264K com.android.SystemLog
32. 2157 17376K 17296K 2683K 2088K com.android.location.fused
33. 2193 17156K 17076K 2663K 2124K com.android.smspush
34. 2590 17364K 17280K 2662K 2092K com.broadcom.phone.register
35. 2943 17112K 17036K 2653K 2056K com.android.musicfx
36. 2619 17132K 17056K 2620K 2040K com.android.voicedialer
37. 2073 17020K 16940K 2603K 1980K com.broadcom.bt.app.fm
38. 2421 17132K 17056K 2530K 1976K com.broadcom.app.autoupdate
39. 1395 33216K 3888K 1859K 1520K /system/bin/surfaceflinger
40. 1394 6544K 3472K 1737K 1468K /system/bin/rild
41. 1403 3216K 3212K 1673K 1524K /system/bin/glgps
42. 2962 1660K 1660K 1413K 1408K procrank
43. 1397 3200K 3200K 1133K 788K /system/bin/drmserver
44. 2148 1604K 1604K 812K 792K /system/bin/wpa_supplicant
45. 1392 1312K 1312K 514K 448K /system/bin/netd
46. 1390 1176K 1176K 418K 360K /system/bin/vold
47. 1400 892K 892K 295K 280K /system/bin/keystore
48. 1450 532K 532K 258K 252K /system/bin/sdcard
49. 1449 228K 228K 208K 208K /sbin/adbd
50. 1408 3572K 500K 199K 172K /system/bin/bkmgrd
51. 1 264K 264K 190K 144K /init
52. 1401 536K 536K 176K 164K /system/bin/akmdfs
53. 1405 444K 444K 169K 160K /system/bin/usb_portd
54. 2905 480K 480K 160K 120K /system/bin/sh
55. 1399 440K 440K 154K 148K /system/bin/installd
56. 2387 392K 392K 149K 144K uuids_sys
57. 1437 464K 464K 148K 108K /system/bin/sh
58. 1393 424K 424K 143K 136K /system/bin/debuggerd
59. 1023 184K 184K 130K 84K /sbin/ueventd
60. 2287 440K 440K 124K 88K sh
61. 2290 440K 440K 124K 88K sh
62. 1389 336K 336K 109K 104K /system/bin/servicemanager
63. 1406 360K 360K 106K 100K /system/bin/atxd_proxy
64. 2289 340K 340K 105K 100K /data/data/com.tencent.qqpimsecure/files/athena_v2.dat
65. ------ ------ ------
66. 241715K 201748K TOTAL
67.
68.RAM: 475520K total, 10412K free, 8104K buffers, 190720K cached, 244K shmem, 27252K slab
2.4 free
free(选项)
-b:以Byte为单位显示内存使用情况;
-k:以KB为单位显示内存使用情况;
-m:以MB为单位显示内存使用情况;
-o:不显示缓冲区调节列;
-s<间隔秒数>:持续观察内存使用状况;
-t:显示内存总和列;
-V:显示版本信息。
执行结果:
free -m
total used free shared buffers cached
Mem: 2016 1973 42 0 163 1497
-/+ buffers/cache: 312 1703
Swap: 4094 0 4094
第一部分Mem行解释:
total:内存总数;
used:已经使用的内存数;
free:空闲的内存数;
shared:当前已经废弃不用;
buffers Buffer:缓存内存数;
cached Page:缓存内存数。
关系:total = used + free
(-buffers/cache) used内存数:第一部分Mem行中的 used – buffers – cached
(+buffers/cache) free内存数: 第一部分Mem行中的 free + buffers + cached
可见-buffers/cache反映的是被程序实实在在吃掉的内存,而+buffers/cache反映的是可以挪用的内存总数。
第三部分是指交换分区。
2.5 showmap
用于查看虚拟地址区域的内存情况。
语法:
showmap -a [pid]
phone:/ # showmap -a 10901
start end virtual shared shared private private
addr addr size RSS PSS clean dirty clean dirty object
-------- -------- -------- -------- -------- -------- -------- -------- -------- ------------------------------
f3b87000 f3d85000 2040 4 4 0 0 4 0 /dev/binder
- start addr和end addr:分别代表进程空间的起止虚拟地址;
- virtual size/ RSS /PSS这些前面介绍过;
- shared clean:代表多个进程的虚拟地址可指向这块物理空间,即有多少个进程共享这个库;
- shared: 共享数据
- private: 该进程私有数据
- clean: 干净数据,是指该内存数据与disk数据一致,当内存紧张时,可直接释放内存,不需要回写到disk
- dirty: 脏数据,与disk数据不一致,需要先回写到disk,才能被释放。
- Object指的是进程里有多少个对象(库),后面是对象或库的名称。
其中Dirty页面如果没有交换机制的情况下,应该是不能回收的。
功能与cat /proc/[pid]/maps
基本一致。
2.6 vmstat
语法:
Usage: vmstat [ -n iterations ] [ -d delay ] [ -r header_repeat ]
-n iterations 数据循环输出的次数
-d delay 两次数据间的延迟时长(单位:S)
-r header_repeat 循环多少次,再输出一次头信息行
vmstat
procs memory system cpu
r b free mapped anon slab in cs flt us ni sy id wa ir
2 0 663436 232836 915192 113960 196 274 0 8 0 2 99 0 0
0 0 663444 232836 915108 113960 180 260 0 7 0 3 99 0 0
0 0 663476 232836 915216 113960 154 224 0 2 0 5 99 0 0
1 0 663132 232836 915304 113960 179 259 0 11 0 3 99 0 0
2 0 663124 232836 915096 113960 110 175 0 4 0 3 99 0 0
参数列总共15个参数,分为4大类:
Procs(进程)
- r: 运行队列中进程数量,这个值也可以判断是否需要增加CPU。(长期大于1)
- b: 等待IO的进程数量。
Memory(内存)
- free: 可用内存大小
- mapped:mmap映射的内存大小
- anon: 匿名内存大小
- slab: slab的内存大小
system(系统)
- in: 每秒中断数,包括时钟中断。
- cs: 每秒上下文切换数。
注意:上面2个值越大,会看到由内核消耗的CPU时间会越大。
CPU(以百分比表示)
- us: 用户进程执行时间百分比(user time)
us的值比较高时,说明用户进程消耗的CPU时间多,但是如果长期超50%的使用,那么我们就该考虑优化程序算法或者进行加速。
- sy: 内核系统进程执行时间百分比(system time)
sy的值高时,说明系统内核消耗的CPU资源多,这并不是良性表现,我们应该检查原因。
- wa: IO等待时间百分比
wa的值高时,说明IO等待比较严重,这可能由于磁盘大量作随机访问造成,也有可能磁盘出现瓶颈(块操作)。
- id: 空闲时间百分比
- ni: nice time
- ir: interrupt time
小结
- dumpsys meminfo适用场景: 查看进程的oom adj,或者dalvik/native等区域内存情况,或者某个进程或apk的内存情况,功能非常强大;
- procrank适用场景: 查看进程的VSS/RSS/PSS/USS各个内存指标;
- cat /proc/meminfo适用场景: 查看系统的详尽内存信息,包含内核情况;
- free适用场景: 只查看系统的可用内存;
- showmap适用场景: 查看进程的虚拟地址空间的内存分配情况;
- vmstat适用场景: 周期性地打印出进程运行队列、系统切换、CPU时间占比等情况;