3

前言

在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 = 正在使用的内存

image.png


所以说,USS 才是进程自己在使用的内存.

那我们平时用 top 获取到的进程内存信息是哪一项呢?

image.png

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_CleanPrivate_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}'

内存分布

同时,我们可以遍历一下文件,统计每个内存映射块的分布。了解进程的内存分布。

例如如下:
image.png

具体代码这里就不再给出。

总结

看完本文,我们了解如何获取进程的VSS,RSS,PSS,USS内容。

并且容易可得: VSS > RSS > PSS > USS。

希望对你有所帮助。


参考:
https://developer.aliyun.com/article/54405
https://blog.csdn.net/armlinuxww/article/details/109022698


weiweiyi
1k 声望123 粉丝