内存管理-31-系统内存统计-5-procrank与procmem
一、VSS/RSS/PSS/USS的区别
1. VSS
Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
VSS表示一个进程可访问的全部内存地址空间的大小。这个大小包括了进程已经申请但尚未使用的内存空间。在实际中很少用这种方式来表示进程占用内存的情况,用它来表示单个进程的内存使用情况是不准确的。
此大小还包括可能不驻留在RAM中的内存,如已分配但未写入的malloc。 VSS对于确定进程的实际内存使用非常少用。
2. RSS:
Resident Set Size 实际使用物理内存(包含共享库占用的内存)
表示一个进程在RAM中实际使用的空间地址大小,包括了全部共享库占用的内存,这种表示进程占用内存的情况也是不准确的。
RSS可能会产生误导,因为它报告进程使用的所有共享库的总数,即使共享库只加载到内存中一次,无论有多少进程使用它。 RSS也不是单个进程的内存使用的准确表示。
3. PSS:
Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
表示一个进程在RAM中实际使用的空间地址大小,它按比例包含了共享库占用的内存。假如有3个进程使用同一个共享库,那么每个进程的PSS就包括了1/3大小的共享库内存。这种方式表示进程的内存使用情况较准确,但当只有一个进程使用共享库时,其情况和RSS一模一样。
当一个进程被销毁时,其占用的那部分PSS又会被按比例地分配给其余使用这些库的进程。
4. USS:
Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
表示一个进程本身占用的内存空间大小,不包含其它任何成分,这是表示进程内存大小的最好方式!
USS是一个非常有用的数字,因为它表示运行特定进程的真正内存增量成本。当进程被终止时,USS是实际返回到系统的总内存。 USS是判断进程中的内存泄漏时最值得注意的数字。
总结:
USS 大小代表只属于本进程正在使用的内存大小,进程被杀死后会被完整回收; VSS/RSS 包含了共享库使用的内存,对查看单一进程内存状态没有参考价值; PSS 是按照比例将共享内存分割后,某单一进程对共享内存区的占用情况。
一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS
二、procrank命令
1. 简介
是一个命令行工具,用于显示Android设备上当前运行的进程的内存使用情况。它可以按照内存使用量对进程进行排序,并显示每个进程的详细信息,如进程名、用户ID、优先级等。
procrank 命令支持多种参数和选项,用于控制输出格式和排序方式:
-v:按照 VSS(Virtual Set Size)排序。
-r:按照 RSS(Resident Set Size)排序。
-p:按照 PSS(Proportional Set Size)排序。
-u:按照 USS(Unique Set Size)排序。
-R:转换为递增(或递减)方式排序。
-w:只显示working set的统计计数。
-W:重置working set的统计计数。
-h:显示帮助信息。
使用场景:
通过 procrank 命令,开发者可以快速定位内存使用量较高的进程,进一步分析是否存在内存泄漏或其他问题。
2. 数据格式
8295:/# procrank PID Vss Rss Pss Uss Swap PSwap USwap ZSwap cmdline 2610 37469604K 2296764K 2111206K 2082692K 69728K 50385K 50052K 17063K com.sam.mapcarlo 1006 10813260K 537836K 314069K 276536K 0K 0K 0K 0K system_server 2821 11469212K 251060K 129777K 122364K 103592K 79893K 79468K 27057K com.sam.UnityService 477 1856892K 197608K 123370K 99312K 0K 0K 0K 0K zygote ... 983 2157852K 1204K 81K 12K 504K 166K 108K 56K /vendor/bin/sh 980 2157852K 1184K 76K 12K 520K 171K 108K 58K /vendor/bin/sh ------ ------ ------ ------ ------ ------ ------ 5354392K 4862732K 2482548K 719121K 649516K 243541K TOTAL ZRAM: 245268K physical used for 724220K in swap (6291452K total swap) RAM: 13792192K total, 2449596K free, 9248K buffers, 4252040K cached, 51752K shmem, 1216120K slab
注: 若开头存在类似 "Failed to open oom_score_adj file: /proc/18501/oom_score_adj" 的打印的话,通常是采样瞬间进程退出导致,属于常见竞态,不影响主结果。
(1) 字段介绍:
Swap 是进程被换出的逻辑大小(未分摊)。
PSwap 是按共享关系分摊后的换出大小(更适合跨进程比较)。
ZSwap 是这些换出页在 zram 里实际占用的物理压缩后大小(真实压缩池成本)。
在 Android + zram 场景下,通常有关系:ZSwap < PSwap <= Swap。
(2) 分析举例:
TOTAL 行:
Swap 2482548K, PSwap 719121K, ZSwap 243541K
这说明:
系统"账面换出"看起来有 2.48GB(Swap),但这里有重复计数问题(共享页在不同进程可重复算)。真正按比例归因后的换出规模约 719MB(PSwap)。这 719MB 被压缩后,实际只占用了约 244MB 的 zram 物理内存(ZSwap)。压缩比大约是 719/244 ≈ 2.95,和底部汇总行一致:
ZRAM: 245268K physical used for 724220K in swap
(3) 进程示例(com.sam.UnityService)
Swap 103592K, PSwap 79893K, ZSwap 27057K
可理解为:
这个进程关联到约 103MB 的换出页账面量。按分摊后约 80MB。真正在 zram 里只占约 27MB 物理空间。压缩比 80/27 接近 3:1,说明 zram 压缩效果正常。
(4) 各字段建议用途
看谁“最可能导致卡顿”: 先看 PSwap(分摊后换出压力), 再看 ZSwap(对 zram 池真实占用), 同时结合 Pss/Uss.
看系统 zram 是否吃紧: 主要看 TOTAL ZSwap 和底部 ZRAM physical used, 再对比 zram total swap 容量(这里是 6291452K)。
这里显示当前 zram 利用率并不高(245MB / 6GB),说明还远没到 swap 容量瓶颈。
(5) 疑问段说明
ZRAM: 245268K physical used for 724220K in swap (6291452K total swap)
这一行是在汇总整机 zram 交换区的“压缩前后”占用关系,拆开看:
"245268K physical used": 表示 zram 设备里当前实际占用的物理内存是 245268KB。这是压缩后真实吃掉 RAM 的大小。
"for 724220K in swap": 表示这些 zram 数据对应的“逻辑换出页总量”是 724220KB。这是压缩前等效大小,也就是系统认为有约 724MB 页面被换到 swap。
"(6291452K total swap)"
表示 zram 总可用 swap 容量是 6291452KB(约 6GB)。相当于 swap 池上限。cat /proc/swaps 和 dumpsys meminfo 和 free -h 都能看 zram 的大小。
三、promem命令
1. 简介
procrank命令从宏观上给出了进程的内存总体情况,但如果需要详细分析某个进程的内存分配细节,这个时候就需要procmem出场了。
procmem使用说明:
# procmem Usage: procmem [ -w | -W ] [ -p | -m ] [ -h ] pid -w Displays statistics for the working set only. -W Resets the working set of the process. -p Sort by PSS. -m Sort by mapping order (as read from /proc). -h Hide maps with no RSS.
2. 命令数据格式
比如下面看surfaceflinger的数据格式
# procmem -p 632 Vss Rss Pss Uss ShCl ShDi PrCl PrDi Name ------- ------- ------- ------- ------- ------- ------- ------- 11080K 4876K 2272K 76K 840K 3960K 4K 72K /vendor/lib64/libllvm-glnext.so 2048K 1852K 1852K 1852K 0K 0K 1852K 0K [anon:libc_malloc] 768K 768K 768K 768K 0K 0K 512K 256K /dev/kgsl-3d0 168K 168K 168K 168K 0K 0K 168K 0K [anon:.bss] 2048K 120K 120K 120K 0K 0K 120K 0K [anon:libc_malloc] 132K 48K 48K 48K 0K 0K 44K 4K [stack] 1016K 12K 12K 12K 0K 0K 12K 0K /dev/binder 可以看出一个binder占1M-2page大小 816K 380K 11K 4K 0K 376K 4K 0K /system/lib64/libc++.so 140K 116K 11K 0K 4K 112K 0K 0K /system/lib64/libui.s 6292K 0K 0K 0K 0K 0K 0K 0K anon_inode:dmabuf ... 11460K 0K 0K 0K 0K 0K 0K 0K anon_inode:dmabuf 4K 0K 0K 0K 0K 0K 0K 0K ------- ------- ------- ------- ------- ------- ------- ------- 2357736K 25984K 16163K 13280K 1488K 11216K 12600K 692K TOTAL
从procmem输出的结果可以看到它给出了内存是如何分配的细节,但面对这茫茫多的输出数据,我们该如何从中寻找问题点呢?
内存异常问题往往伴随着内存泄露,而内存泄露的本质就是申请的内存区域得不到正常释放,表现在procmem的输出结果就是多条同名的记录出现。因此如果发现procmem输出的结果里某条记录出现次数过多,比如五六百次,那么我们应当小心对待了。
posted on 2021-11-30 20:07 Hello-World3 阅读(2589) 评论(0) 收藏 举报
浙公网安备 33010602011771号