内存管理-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)    收藏  举报

导航