前言
在linux系统中, 我们往往会使用 top 命令获取系统内存,以及大致的进程内存。 实际上,进程内存还会包括共享库,即多个进程都使用一份共享库,仅消耗一份共享库的内存。 所以,要分析linux 进程内存,我们需要先了解相关概念再进行获取。
进程内存概览
实际上,进程的内存有四个指标: VSS,RSS, PSS, USS.
VSS (Virtual Set Size)
虚拟耗用内存大小,是进程可以访问的所有虚拟内存的总量。包括进程独自占用的物理内存、和其他进程共享的内存、分配但未使用的内存。
RSS (Resident Set Size)
驻留内存大小,是进程当前实际占用的物理内存大小,包括进程独自占用的物理内存、和其他进程共享的内存。
PSS (Proportional Set Size)
比例驻留内存大小,包括进程独自占用的物理内存、比例分配和其他进程共享的内存(共享库内存会均分到各个共享进程)。
USS (Unique Set Size)
独立内存大小,表示进程独自占用、不与其他进程共享的物理内存。
比如,一个进程A:
VSS = 分配的内存 + 共享库内存
RSS = 正在使用的内存+ 共享库内存
PSS = 正在使用的内存+ 共享库内存 / 共享内存个数
USS = 正在使用的内存
所以说,USS 才是进程自己在使用的内存.
那我们平时用 top 获取到的进程内存信息是哪一项呢?
VIRT (Virtual Memory Size): 对应进程的 VSS。
RES:(Resident Set Size): 对应进程的 RSS
SHR(Shared Memory Size): 进程所使用的共享内存大小, 相当于共享库内存 / 共享内存个数
进程内存获取
我们可以从 /proc 文件目录下获取一些内存信息。
关于 /proc, 对于不了解的人介绍一下:
proc是Linux系统下的一个虚拟文件系统,它不存在于磁盘, 而是存在于系统内存中。 所以当你使用 ls -al /proc这条命令来查看proc目录时, 会看到其下面的所有文件的大小都为0字节。
proc以文件系统的方式为访问系统内核的操作提供接口。 很多系统的信息, 如内存使用情况, cpu使用情况,进程信息等等这些信息,都可以通过查看/proc下的对应文件来获得。
proc文件系统是动态从系统内核读出所需信息的。
所以,我们访问系统内存信息可以访问 /proc/meminfo
获取。
例如
cat /proc/meminfo
MemTotal: 515492 kB
MemFree: 8452 kB
Buffers: 19724 kB
Cached: 376400 kB
SwapCached: 4 kB
而我们访问进程内存的信息则存在于: /proc/PID/smaps
下。
/proc/1/smaps
文件信息如下:
08048000-080bc000 r-xp 00000000 03:02 13130 /bin/bash
Size: 1084 kB
Rss: 892 kB
Pss: 374 kB
Shared_Clean: 892 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 892 kB
Anonymous: 0 kB
ShmemPmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
THPeligible: 0
VmFlags: rd ex mr mw me dw
文件里包含进程的多个VMA(虚拟内存区域), 每一个VMA都有如上的一系列数据
- 08048000-080bc000 地址空间的开始地址 - 结束地址
- r-xp 内存段的权限,分别是可读、可写、可运行、私有或共享,最后一位p代表私有,s代表共享
- 00000000 如果这段内存是从文件里映射过来的,则偏移量为这段内容在文件中的偏移量。如果不是从文件里面映射过来的则为0.
- 03:02 文件的主设备号和次设备号。
- 13130 文件号,即/bin/bash的文件号
- /bin/bash 被映射到虚拟内存的文件名称。
里面有几项比较重要的属性:
Rss: 892 kB
Pss: 374 kB
Shared_Clean: 892 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
输出了该内存区域的RSS, Pss。
所以 我们只需要累加所有内存区域的RSS,PSS 就可以了。
RSS
# 查看进程所有内存区域的RSS:
cat /proc/23716/smaps | grep Rss
#累加
cat /proc/23716/smaps | grep Rss | awk '{sum += $2} END {print sum}'
PSS
# 查看进程所有内存区域的PSS:
cat /proc/23716/smaps | grep Pss
# 累加
cat /proc/23716/smaps | grep Pss | awk '{sum += $2} END {print sum}'
USS
而获取USS, 我们需要累加内存区域的 Private_Clean 和 Private_Dirty 的属性
Private_Clean:表示该内存区域是进程私有的,干净的,没有被修改
Private_Dirty: 该内存区域是进程私有的,并且其内容在内存中是脏的,即与相应的文件内容不同,已经被修改过。即没有跟磁盘文件同步。
而这两项属性并不包括共享内存,所以我们可以累加这两项属性就可以得到USS。
# 查看
cat /proc/23716/smaps | grep Private_
# 累加
cat /proc/23716/smaps | grep Private_ | awk '{sum += $2} END {print sum}'
VSS
内存区域的 Size属性表示表示进程虚拟内存的大小,所以我们累加所有内存区域的 Size 属性 就可以获取 VSS。
# 查看
cat /proc/23716/smaps | grep Size
# 累加
cat /proc/23716/smaps | grep Size | awk '{sum += $2} END {print sum}'
内存分布
同时,我们可以遍历一下文件,统计每个内存映射块的分布。了解进程的内存分布。
例如如下:
具体代码这里就不再给出。
总结
看完本文,我们了解如何获取进程的VSS,RSS,PSS,USS内容。
并且容易可得: VSS > RSS > PSS > USS。
希望对你有所帮助。
参考:
https://developer.aliyun.com/article/54405
https://blog.csdn.net/armlinuxww/article/details/109022698
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。