1、如何查看memory 的总消耗
linux的命令top -h 以及PS 都可以查看到内存PSS和VSS的内存消耗。android提供了工具,可以更全面的分析到内存的分布情况。先看procrank,这个工具没有,可以通过下载编译放在android /system/xbin/目录下。然后分别执行:
adb root
adb shell procrank
我们看一下内存分布结果:
PID Vss Rss Pss Uss Swap PSwap USwap ZSwap cmdline
1012 1552016K 214564K 131199K 120700K 25304K 20554K 20356K 10391K xxx.xxxx.xxx(进程名)
我们发现一个关系,VSS>RSS>PSS>USS(实际都是>=),那他们有什么区别呢?为什么存在大小差别。
首先是VSS,Virtual Set Size,也就是虚拟耗用内存,它包含了所有的分配的内存,这部分内存有可能还未使用。所以称为虚拟。除了包含本进程的分配内存,它还包含了共享库的内存。
RSS,Resident Set Size ,实际使用物理内存,因此他只包含了使用的内存,他除了包含自己使用的内存,还包含了所有的共享库的内存。
PSS,Proportional Set Size,实际使用物理内存,上面RSS讲到,会将所有的共享库的内存都算进来,如果很多程序都在使用共享库的内存,会造成全算到一个进程RSS里面,显然是不准确的,PSS则将共享库内存进行平均,算到每一个使用其的PSS内存里。
Uss,Unique Set Size ,进程独自占用内存,顾名思义,就是剥离了共享库的内存值。这个能更精确的反应当前进程本身的内存使用状况。
注:共享的内存怎么理解,比如调用很多公有服务,使用公有的库,这部分库的内存实际只会载入一次,所以这部分的内存归属问题,才有了现在这么多分组。
2、如何查看应用具体内存情况
这个就是我们常用的adb shell dumpsys meminfo xxxx(进程名)。
为什么我们这边一定强调一定是进程名,因为linux的内存页分配都是以进程为单位的,虽然默认情况下单进程的app,进程名就是app的包名。但是必须要强调。
我们看一个结果:
Applications Memory Usage (in Kilobytes):
Uptime: 3168126 Realtime: 3168126
** MEMINFO in pid 1012 [XXX.XXX.XXX(进程名)] **
Pss Private Private SwapPss Heap Heap Heap
Total Dirty Clean Dirty Size Alloc Free
------ ------ ------ ------ ------ ------ ------
Native Heap 27293 27056 196 3695 38144 30571 7572
Dalvik Heap 12776 12416 336 1993 18601 12473 6128
Dalvik Other 1737 1736 0 2
Stack 36 36 0 0
Ashmem 4390 4372 0 0
Other dev 30 4 20 0
.so mmap 13517 6220 2684 2625
.apk mmap 4083 72 2668 6316
.ttf mmap 510 0 452 0
.dex mmap 53489 24080 26868 6232
.oat mmap 2094 0 532 0
.art mmap 5876 5264 216 12
Other mmap 6507 4 6220 0
EGL mtrack 28021 28021 0 0
GL mtrack 26319 26319 0 0
Unknown 2448 2380 68 415
TOTAL 210416 137980 40260 21290 56745 43044 13700
App Summary
Pss(KB)
------
Java Heap: 17896
Native Heap: 27056
Code: 63576
Stack: 36
Graphics: 54340
Private Other: 15336
System: 32176
TOTAL: 210416 TOTAL SWAP PSS: 21290
Objects
Views: 681 ViewRootImpl: 3
AppContexts: 7 Activities: 1
Assets: 5 AssetManagers: 3
Local Binders: 151 Proxy Binders: 53
Parcel memory: 30 Parcel count: 121
Death Recipients: 2 OpenSSL Sockets: 5
WebViews: 0
SQL
MEMORY_USED: 1105
PAGECACHE_OVERFLOW: 822 MALLOC_SIZE: 117
可以看到这块内存主要字段有pss,private。我们从上往下看。
pss total,就对应我们上一节中提到的pss,它包含了应用自己的内存,还包含了共享(或跨进程)使用的内存。
相应的private dirty就表示,就是独自占用的脏页的内存值,脏页在linux里就表示高速缓存(在物理内存中)中被修改的内存页。相反private clean就表示高速缓存中未被修改的页。
swap内存,因为内存缓存机制,会基于最近最少使用的缓存原则,将内存中长时间不运行的数据,缓存到硬盘中,这部分数据到了硬盘中,swap之后的这部分内存称为虚拟内存,在需要使用的时候,才会从硬盘中读取出来。
所以实际上,我们就把private相关的值就表示应用本身的内存占用情况,相应的pss则增加了共享库内存的内存使用。
除了这块内存参数以外,还有heap size、heap alloc 和 heap free。
heap alloc表示我们在分配的内存大小,heap free就表示空闲的内存大小。heap size则表示最大可分配的内存大小,相当于heap alloc 和 heap free的和。
我们在看一下每个内存的分类情况:
Dalvik Heap:Dalvik虚拟机分配的内存。
Native Heap:本地代码申请的内存。
.so mmap 、.dex mmap … mmap 映射本地或虚拟机代码到使用的内存中。
Unknown 无法归类的其他项。主要包括大部分的本地分配。
App summary中内存,则统计的都是private的相关内存,其中包括了:
Java Heap java的堆内存
Native Heap 本地代码的内存
Code 代码申请的内存
Stack 栈内存
Graphics 物理内存
Private Other 其他内存
System 系统内存
Objects 就包含了android中所使用的对象了,ViewRootImpl用于分析window的数量。Activities则表示activity的数量Proxy Binders,则表示本地建立binder 的数量,WebViews则表示使用webview的数量,均是发生内存泄漏的高频区,利于分析。
SQL,则是数据库使用的内存情况。