Android Memeory Debug Tips

Android Memeory Debug Tips

Android Memeory Debug Tips

0, outline

  1. 1,dumpsys meminfo(/$pid)(as similar with cat /proc/PID/smaps)
  2. 2,procrank (as similar with cat /proc/$pid/status )
  3. 3,free
  4. 4,cat /proc/meminfo
  5. 5,echo m > proc/sysrq-trigger

1,在Android5.1上dumpsys meminfo的输出结果如下:

  1. shell@p200:/ # dumpsys meminfo
  2. Applications Memory Usage (kB):
  3. Uptime: 73930414 Realtime: 73930414
  4. Total PSS by process:
  5. 145252 kB: com.moretv.android (pid 5156 / activities)
  6. 62302 kB: surfaceflinger (pid 2739)
  7. 44357 kB: mediaserver (pid 2796)
  8. ...
  9. Total PSS by OOM adjustment:
  10. 117272 kB: Native
  11. 62302 kB: surfaceflinger (pid 2739)
  12. 44357 kB: mediaserver (pid 2796)
  13. 2179 kB: zygote (pid 2808)
  14. 1425 kB: logd (pid 2733)
  15. 992 kB: sdcard (pid 4019)
  16. 920 kB: sdcard (pid 2751)
  17. 537 kB: netd (pid 2793)
  18. 494 kB: /init (pid 1)
  19. 409 kB: dumpsys (pid 7150)
  20. 381 kB: systemcontrol (pid 2801)
  21. 371 kB: dhcpcd (pid 4861)
  22. 66836 kB: Persistent
  23. 38218 kB: system (pid 3093)
  24. 20257 kB: com.android.systemui (pid 3826)
  25. 3135 kB: com.droidlogic.SubTitleService (pid 4087)
  26. ...
  27. 145252 kB: Foreground
  28. 145252 kB: com.moretv.android (pid 5156 / activities)
  29. 5514 kB: Visible
  30. 5514 kB: com.moretv.middleware.moretvdaemon (pid 5195)
  31. 5633 kB: Perceptible
  32. 5633 kB: com.android.inputmethod.latin (pid 4032)
  33. 38438 kB: Home
  34. 38438 kB: com.droidlogic.mboxlauncher (pid 4107 / activities)
  35. 20233 kB: Previous
  36. 20233 kB: com.moretv.tvapp (pid 5034 / activities)
  37. 16277 kB: B Services
  38. 7454 kB: com.android.tv.settings (pid 4406)
  39. 6290 kB: com.elinkway.tvlive2.beta (pid 5213)
  40. 2533 kB: com.droidlogic.PPPoE (pid 4473)
  41. 41239 kB: Cached
  42. 10732 kB: com.android.packageinstaller (pid 4557)
  43. 5829 kB: android.process.media (pid 6986)
  44. 4990 kB: com.android.music (pid 6966)
  45. 4830 kB: android.process.acore (pid 4195)
  46. ...
  47. Total PSS by category:
  48. 136400 kB: Dalvik
  49. 114044 kB: Native
  50. 59416 kB: GL mtrack
  51. 56204 kB: EGL mtrack
  52. 19314 kB: .art mmap
  53. 19229 kB: .so mmap
  54. 15457 kB: .oat mmap
  55. 11482 kB: .dex mmap
  56. ...
  57. Total RAM: 851640 kB (status normal)
  58. Free RAM: 250263 kB (41239 cached pss + 141868 cached kernel + 67156 free)
  59. Used RAM: 555971 kB (415455 used pss + 140516 kernel)
  60. Lost RAM: 45406 kB
  61. ZRAM: 4740 kB physical used for 15060 kB in swap (511996 kB total swap)
  62. Tuning: 192 (large 512), oom 106496 kB, restore limit 108333 kB (high-end-gfx)
主要分为4块内容,Total PSS by process是按各个进程的PSS的大小排序,可以通过cat /proc/$pid/status来查看对应的PSS;Total PSS by OOM adjustment是调整的值,Total PSS by categoty是各个so库,或者dex占用的内存的大小。以上三种只是不同的统计方法。最后有一个summary,可以和free -m命令的对应起来看,free -m在后面再讲。

2, procrank输出如下:

  1. shell@p200:/ # procrank
  2. [ 6500.012332] CPU1: Booted secondary processor
  3. PID Vss Rss Pss Uss cmdline
  4. 3519 1605848K 81840K 51783K 48252K com.droidlogic.mboxlauncher
  5. 3054 1596760K 74092K 39529K 33132K system_server
  6. 3244 1519620K 48544K 18466K 15076K com.android.systemui
  7. 2795 1488148K 50248K 15451K 9400K zygote
  8. 3441 1514280K 38324K 9132K 6492K com.android.inputmethod.latin
  9. 2785 72172K 12736K 8890K 7628K /system/bin/mediaserver
  10. 3206 1501084K 34736K 7183K 4832K android.process.media
  11. 2710 101600K 8944K 4891K 3936K /system/bin/surfaceflinger
  12. 3713 1498784K 31076K 4803K 2948K com.android.providers.calendar
  13. 3826 1501480K 30936K 4718K 2936K com.android.deskclock
  14. 3653 1498508K 30488K 4591K 2784K com.android.music
  15. 3806 1503168K 28704K 4310K 2860K com.android.tv.settings
  16. 3501 1497964K 29868K 3935K 2180K com.droidlogic.SubTitleService
  17. 3873 1497624K 28980K 3709K 2008K com.droidlogic.PPPoE
  18. 3737 1501984K 26760K 3346K 2000K com.droidlogic.mediacenter
  19. 3759 1497588K 27452K 3257K 1844K com.android.managedprovisioning
  20. 3853 1496740K 27180K 3103K 1704K com.droidlogic.otaupgrade
  21. 3481 1496540K 26652K 3029K 1640K com.droidlogic.service.remotecontrol
  22. 4091 1496676K 26648K 2955K 1484K com.android.musicfx
  23. 3784 1496496K 26760K 2947K 1556K com.android.onetimeinitializer
  24. 2784 26080K 5632K 2822K 1964K /system/bin/drmserver
  25. 3463 1496804K 25152K 2808K 1504K com.droidlogic.inputmethod.remote
  26. 2793 41684K 6188K 2616K 1632K /system/bin/imageserver
  27. 2705 22740K 1644K 1035K 992K /system/bin/logd
  28. 2709 18036K 1964K 964K 856K /system/bin/vold
  29. 2790 17432K 1632K 849K 796K /system/bin/systemcontrol
  30. 2788 12500K 1888K 777K 640K /system/bin/keystore
  31. 2782 22840K 1388K 769K 704K /system/bin/netd
  32. 1 17060K 872K 709K 576K /init
  33. 12539 9192K 956K 641K 628K procrank
  34. 2707 10628K 1208K 488K 348K /system/bin/lmkd
  35. 2792 10452K 1112K 480K 412K /system/bin/pppoe_wrapper
  36. 1851 8864K 580K 446K 316K /sbin/ueventd
  37. 2775 17456K 772K 432K 420K /system/bin/sdcard
  38. 2796 16980K 408K 388K 388K /sbin/adbd
  39. 2783 10056K 884K 346K 316K /system/bin/debuggerd
  40. 2706 9824K 348K 344K 344K /sbin/healthd
  41. 5796 8768K 444K 320K 200K sh
  42. 2708 9460K 672K 314K 300K /system/bin/servicemanager
  43. 2781 8768K 436K 312K 192K /system/bin/sh
  44. 2787 9416K 680K 306K 292K /system/bin/installd
  45. 2794 8760K 332K 305K 304K /system/bin/dig
  46. 3690 9256K 552K 221K 208K /system/bin/usbtestpm
  47. ------ ------ ------
  48. 218737K 169024K TOTAL
  49. RAM: 851720K total, 203600K free, 12812K buffers, 307260K cached, 232K shmem, 36080K slab

内存相关名词解释:VSS/RSS/PSS/USS
VSS Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
RSS Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PSS Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
USS Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS
如果要检测内存是否泄露, USS 是一个非常重要的值。

那么,buffers cached shmem slab分别是指什么?
有一个类似的功能,cat /proc/$pid/status,我们以上图的4091 PID为例:

  1. shell@p200:/ # cat /proc/4091/sta
  2. stack stat statm status
  3. shell@p200:/ # cat /proc/4091/status
  4. Name: android.musicfx
  5. State: S (sleeping)
  6. Tgid: 4091
  7. Ngid: 0
  8. Pid: 4091
  9. PPid: 2795
  10. TracerPid: 0
  11. Uid: 10008 10008 10008 10008
  12. Gid: 10008 10008 10008 10008
  13. FDSize: 64
  14. Groups: 3002 3003 9997 50008
  15. VmPeak: 1496884 kB
  16. VmSize: 1496680 kB
  17. VmLck: 0 kB
  18. VmPin: 0 kB
  19. VmHWM: 26420 kB
  20. VmRSS: 26236 kB
  21. VmData: 130564 kB
  22. VmStk: 8196 kB
  23. VmExe: 12 kB
  24. VmLib: 63548 kB
  25. VmPTE: 352 kB
  26. VmSwap: 0 kB
  27. Threads: 13
  28. SigQ: 0/1921
  29. SigPnd: 0000000000000000
  30. ShdPnd: 0000000000000000
  31. SigBlk: 0000000000001204
  32. SigIgn: 0000000000000000
  33. SigCgt: 00000002000094f8
  34. CapInh: 0000000000000000
  35. CapPrm: 0000000000000000
  36. CapEff: 0000000000000000
  37. CapBnd: 0000000000000000
  38. Seccomp: 0
  39. Cpus_allowed: f
  40. Cpus_allowed_list: 0-3
  41. voluntary_ctxt_switches: 18
  42. nonvoluntary_ctxt_switches: 46

VmPeak: 表示进程所占用最大虚拟内存大小
VmSize: 表示进程当前虚拟内存大小
VmLck: 表示被锁定的内存大小
VmHWM: 表示进程所占用物理内存的峰值
VmRSS: 表示进程当前占用物理内存的大小(与procrank中的RSS)
VmData: 表示进程数据段的大小
VmStk: 表示进程堆栈段的大小
VmExe: 表示进程代码的大小
VmLib: 表示进程所使用共享库的大小
VmPTE: 表示进程页表项的大小

3, 最基础的free命令的输出

  1. shell@p200:/system/usr/keylayout # free
  2. total used free shared buffers
  3. Mem: 851636 617288 234348 0 1460
  4. -/+ buffers: 615828 235808
  5. Swap: 511996 1048 510948

在X86的平台上,还稍微有点区别,多一行cached,在ARM平台合成一项了叫做buffers.
先解释下,buffer与cacehd有区别

  1. A buffer is something that has yet to be "written" to disk.
  2. A cache is something that has been "read" from the disk and stored for later use.

那ARM上,读与写都是使用buffers来替代。
使用这个命令,可以把buffers回收一部分

  1. echo 3>/proc/sys/vm/drop_caches

在第二行,两个数据分别是表示-buffers的used值,和+buffers的free值。可以理解,buffer理论上可以回收的。
所以 

  1. 615828 = 617288 - 1460
  2. 235808 = 234348 + 1460

swap,在ARM平台上,swap并不是在硬盘(flash)开辟一个分区,众所周知,IO访问速度太慢了,现在配合使用zram技术,swap的total值,现在仅是一个最大的门限值了。used1048,并不是占用1048kb的大小,因为使用了zram的压缩技术,理论上是一个远小于1048的值。可以通过dumpsys meminfo来查看具体。808KB,呵呵,其实也没有远小于。

  1. ZRAM: 808 kB physical used for 1048 kB in swap (511996 kB total swap)
4, cat /proc/meminfo
我想理解以上三个命令,这个命令只是不同的表示方式了。先看平台的输出
  1. shell@p200:/proc/2739 # cat /proc/meminfo
  2. MemTotal: 851640 kB
  3. MemFree: 157812 kB
  4. MemAvailable: 403612 kB
  5. Buffers: 49228 kB
  6. Cached: 209952 kB
  7. SwapCached: 1116 kB
  8. Active: 150908 kB
  9. Inactive: 296924 kB
  10. Active(anon): 70528 kB
  11. Inactive(anon): 137780 kB
  12. Active(file): 80380 kB
  13. Inactive(file): 159144 kB
  14. Unevictable: 8076 kB
  15. Mlocked: 0 kB
  16. SwapTotal: 511996 kB
  17. SwapFree: 496952 kB
  18. Dirty: 0 kB
  19. Writeback: 0 kB
  20. AnonPages: 196060 kB
  21. Mapped: 71972 kB
  22. Shmem: 11580 kB
  23. Slab: 43636 kB
  24. SReclaimable: 20100 kB
  25. SUnreclaim: 23536 kB
  26. KernelStack: 10192 kB
  27. PageTables: 10828 kB
  28. NFS_Unstable: 0 kB
  29. Bounce: 0 kB
  30. WritebackTmp: 0 kB
  31. CommitLimit: 937816 kB
  32. Committed_AS: 27934916 kB
  33. VmallocTotal: 251658176 kB
  34. VmallocUsed: 70040 kB
  35. VmallocChunk: 251499268 kB
  36. HugePages_Total: 0
  37. HugePages_Free: 0
  38. HugePages_Rsvd: 0
  39. HugePages_Surp: 0
  40. Hugepagesize: 2048 kB
这里面有一些信息,其它是没有的,比较buffer和cached的值。
Buffers: 用来给文件做缓冲大小。
Cached: 被高速缓冲存储器(cache memory)用的内存的大小(等于diskcache minus SwapCache)。 
SwapCached:被高速缓冲存储器(cache memory)用的交换空间的大小。已经被交换出来的内存,仍然被存放在swapfile中,用来在需要的时候很快的被替换而不需要再次打开I/O端口。 
还有ANON
Active: 在活跃使用中的缓冲或高速缓冲存储器页面文件的大小,除非非常必要,否则不会被移作他用。 
Inactive: 在不经常使用中的缓冲或高速缓冲存储器页面文件的大小,可能被用于其他途径。
AnonPages:未映射页的内存大小。Active = Active(anon)+Active(file),同理Inactive也满足这个等式。
  1. Active: 150908 kB
  2. Inactive: 296924 kB
  3. Active(anon): 70528 kB
  4. Inactive(anon): 137780 kB
  5. Active(file): 80380 kB
  6. Inactive(file): 159144 kB
还在Slab缓冲器相关的
Slab: 内核数据结构缓存的大小,可以减少申请和释放内存带来的消耗。 
SReclaimable:可收回Slab的大小。 
SUnreclaim:不可收回Slab的大小(SUnreclaim+SReclaimable=Slab)。

5,最后一个echo m > /sys/sysrq-trigger

  1. shell@p200:/ # echo m >/proc/sysrq-trigger
  2. [ 567.335169] SysRq : Show Memory
  3. [ 567.335339] Mem-Info:
  4. [ 567.335439] DMA per-cpu:
  5. [ 567.337502] CPU 0: hi: 186, btch: 31 usd: 138
  6. [ 567.342307] active_anon:33208 inactive_anon:51 isolated_anon:0
  7. [ 567.342307] active_file:7386 inactive_file:76365 isolated_file:0
  8. [ 567.342307] unevictable:0 dirty:0 writeback:0 unstable:0
  9. [ 567.342307] free:45158 slab_reclaimable:3918 slab_unreclaimable:5128
  10. [ 567.342307] mapped:20339 shmem:57 pagetables:2388 bounce:0
  11. [ 567.342307] free_cma:1
  12. [ 567.373841] DMA free:180632kB min:3684kB low:4604kB high:5524kB active_anon:132832kB inactive_anon:204kB active_file:29544kB inactive_file:305460kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:997376kB managed:849572kB mlocked:0kB dirty:0kB writeback:0kB mapped:81356kB shmem:228kB slab_reclaimable:15672kB slab_unreclaimable:20512kB kernel_stack:8432kB pagetables:9552kB unstable:0kB bounce:0kB free_cma:4kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no
  13. [ 567.415623] lowmem_reserve[]: 0 0 0
  14. [ 567.419077] DMA: 394*4kB (UMC) 342*8kB (UEM) 186*16kB (UEM) 117*32kB (UEM) 88*64kB (UEM) 57*128kB (UM) 44*256kB (U) 42*512kB (UEM) 41*1024kB (U) 2*2048kB (UM) 19*4096kB (M) = 180632kB
  15. [ 567.435317] Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
  16. [ 567.443659] 83803 total pagecache pages
  17. [ 567.447468] 0 pages in swap cache
  18. [ 567.450741] Swap cache stats: add 0, delete 0, find 0/0
  19. [ 567.455910] Free swap = 511996kB
  20. [ 567.459183] Total swap = 511996kB
  21. [ 567.462462] 249344 pages RAM
  22. [ 567.465306] 0 pages HighMem/MovableOnly
  23. [ 567.469102] 36951 pages reserved
这个很多内容跟cat /proc/meminfo类似,但也有些其它的,比如DMA的描述部分。
看DMA部分,可以先看下系统的buddyinfo,就知道是对应的,表示当前内存碎片的情况
  1. shell@p200:/ # cat /proc/buddyinfo
  2. Node 0, zone DMA 393 342 186 117 88 57 44 42 41 2 19
这里面的DMA在64bit的系统中,如果物理内存少于4G,表示整个内存。参考资料中有说明:
DMA is the low 16 MBytes of memory. At this point it exists for historical reasons; once upon what is now a long time ago, there was hardware that could only do DMA into this area of physical memory.
DMA32 exists only in 64-bit Linux; it is the low 4 GBytes of memory, more or less. It exists because the transition to large memory 64-bit machines has created a class of hardware that can only do DMA to the low 4 GBytes of memory.
(This is where people mutter about everything old being new again.)
 
Normal is different on 32-bit and 64-bit machines. On 64-bit machines, it is all RAM from 4GB or so on upwards. On 32-bit machines it is all RAM from 16 MB to 896 MB for complex and somewhat historical reasons.
Note that this implies that machines with a 64-bit kernel can have very small amounts of Normal memory unless they have significantly more than 4GB of RAM. For example, a 2 GB machine running a 64-bit kernel will have no Normal memory at all while a 4 GB machine will have only a tiny amount of it.
 
HighMem exists only on 32-bit Linux; it is all RAM above 896 MB, including RAM above 4 GB on sufficiently large machines.
我试图想翻译这段,还是算了,怕说错了误导。直接看下不难。也就是在32bit的64bit的架构中,zones的划分有区别。所以在32bit的系统中表示又不一样了
  1. 130|root@m201:/ # cat /proc/buddyinfo
  2. Node 0, zone Normal 1342 1021 753 436 193 63 40 18 12 5 71
  3. Node 0, zone HighMem 81 24 11 11 2 6 5 3 2 2 2
6,And More
  • 以上内容是假设你已经理解了物理内存,虚拟内存,以及逻辑内存的区别
  • 涉及到Android的内存管理还有其它的模块,比如ION,CMA,Buddy系统等等,每个深入都是一大块。
  • 参考资料:android L framworks/
  • 参考资料:https://utcc.utoronto.ca/~cks/space/blog/linux/KernelMemoryZones
TOP