Linux 进程内存监控:Linux 内存调优之进程内存深度监控

举报
山河已无恙 发表于 2025/04/12 15:51:07 2025/04/12
【摘要】 写在前面博文内容涉及 Linux 进程内存监控监控方式包括传统工具 ps/top/pmap ,以及 cgroup 内存子系统,proc 内存伪文件系统监控内容包括进程内存使用情况, 内存全局数据统计,内存事件指标,以及进程内存段数据监控理解不足小伙伴帮忙指正 :),生活加油 我看远山,远山悲悯持续分享技术干货,感兴趣小伙伴可以关注下 ^_^监控进程的内存使用量这里分析的工具主要是原生工具,后...

写在前面


  • 博文内容涉及 Linux 进程内存监控
  • 监控方式包括传统工具 ps/top/pmap ,以及 cgroup 内存子系统,proc 内存伪文件系统
  • 监控内容包括进程内存使用情况, 内存全局数据统计,内存事件指标,以及进程内存段数据监控
  • 理解不足小伙伴帮忙指正 :),生活加油

我看远山,远山悲悯

持续分享技术干货,感兴趣小伙伴可以关注下 ^_^


监控进程的内存使用量

这里分析的工具主要是原生工具,后面还会分享一些 BPF 相关的内存观察工具以及系统内存的全局监控

PS/TOP

一般的内存监控工具,对于进程级别的,会使用如 ps/top 命令, 通过指标 VIRT 或 VSZ 和 RES 或 RSS 来区分两种不同的统计数据

  • VIRT 或 VSZ 代表进程申请的虚拟内存大小,
  • RES 或 RSS 代表的是虚拟内存当前实际映射的物理内存大小,也叫常驻内存。
┌──[root@vms100.liruilongs.github.io]-[~]
└─$top
top - 11:46:44 up 8 min,  1 user,  load average: 6.52, 17.45, 10.38
Tasks: 449 total,   1 running, 448 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.9 us,  1.1 sy,  0.0 ni, 96.8 id,  0.0 wa,  0.6 hi,  0.5 si,  0.0 st
MiB Mem :  15730.5 total,   7503.6 free,   7147.4 used,   1079.5 buff/cache
MiB Swap:   2068.0 total,   2068.0 free,      0.0 used.   8177.7 avail Mem

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
   1947 42418     20   0  555196 132972  20272 S   1.3   0.8   0:12.86 heat-engine
  10320 42436     20   0  540276 122200  17492 S   1.3   0.8   0:08.95 nova-scheduler
    949 root      20   0  694072  31640  16876 S   1.0   0.2   0:16.58 tuned
   1945 42415     20   0  749212 142564  34988 S   1.0   0.9   0:12.38 glance-api
   1965 42436     20   0  540120 121848  17324 S   1.0   0.8   0:12.16 nova-conductor
  15567 root      20   0  269540   5228   4160 R   1.0   0.0   0:00.05 top
  ..........................................

所以如果通过上面的命令,查看应用实际使用的内存大小,需要查看 RES(RSS(KB单位)) 列,表示进程当前驻留在物理内存中的内存总量(即没有被交换到磁盘的部分)。

RSS 包含的内容​​:

  • 进程独有的数据(如堆、栈、私有匿名页)。 ​​+ 共享内存页​​(如共享库、共享内存 IPC 等)。
┌──[root@liruilongs.github.io]-[~]
└─$ps -e -o pid,vsz,rss,comm | awk '$2 > 0 {print}'
    PID    VSZ   RSS COMMAND
      1 170808 14208 systemd
    704  26824 11520 systemd-journal
    719  34968 12160 systemd-udevd
    892  18156  4540 auditd
    913  10796  4736 dbus-broker-lau
。。。。。。。。。。
   4177   6664  3712 awk
┌──[root@liruilongs.github.io]-[~]
└─$

共享内存

需要说明的是,进程是共享物理内存页帧的。比如使用相同库函数的两个进程,就可以共享使用相同的物理内存页来存储库文件代码。它们各自的 ​​RSS(Resident Set Size)​​ 值会将该共享页的物理内存(SHR 列)重复计入每个进程的 RSS(RES)。因此 ​​进程的 RSS 总和​​ 可能会明显超过 ​​系统实际的物理内存容量​​。真实物理内存占用 = ​​独占内存(RES) - 共享内存​SHR​​(Shared Memory)​。

SHR列 ​​:进程占用的 ​​共享物理内存​​(如共享库、共享内存 IPC)。

Cgroup 子系统

通过 Cgroup 子系统来获取内存信息,在获取之前需要获取当前进程的PID以及对应的 Cgroup 分组

获取 htop 进程ID, htop 是一个类似 top 的系统整体性能监控的进程

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$pgrep htop
4150

通过 ps 命令获取 htop 对应的 Cgroup 分组

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$ps -o cgroup 4150
CGROUP
11:pids:/user.slice/user-1000.slice/session-1.scope,
8:memory:/user.slice/user-1000.slice/session-1.scope,
2:devices:/user.slice,
1:name=systemd:/user.slice/user-1000.sli
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$

我们只关注内存子系统的,所以直接看内存的分组: 8:memory:/user.slice/user-1000.slice/session-1.scope,这里的 8 表示 Cgroup 层级

可以通过下面的命令查看 Cgroup 层级以及 当前系统挂载了多少子系统

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat /proc/cgroups
#subsys_name hierarchy num_cgroups enabled
cpuset 4 1 1
cpu     6 3 1
cpuacct 6 3 1
blkio   9 1 1
memory 8 91 1
devices 2 43 1
freezer 13 1 1
net_cls 12 1 1
perf_event 5 1 1
net_prio 12 1 1
hugetlb 7 1 1
pids 11 52 1
rdma 3 1 1
files 10 1 1
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$

user.slice/user-1000.slice/session-1.scope 表示 Cgroup 层级树

  • user.slice​​:表示该 cgroup 属于 ​​用户会话层级​​,与用户进程相关(与 system.slice 系统服务层级区分)
  • user-1000.slice​​:表示用户 ID 为 ​​1000​​ 的普通用户(Linux 中 UID 1000 通常是首个创建的非 root 用户)
  • session-1.scope​​:表示该用户的 ​​会话单元​​(如一个终端会话或登录会话),属于临时性资源组(scope 用于管理短生命周期的进程组)

htop 是一个前台进程,通过 Cgroup 资源树可以很清晰的看到,下面来看下 Cgroup 内存子系统观察进程内存信息的一些指标文件

内存详细信息指标监控

下面一组是内存详细信息的数据统计

参数 作用
memory.numa_stat NUMA 节点的内存使用统计(适用于多 CPU 架构)。
memory.stat 详细内存使用统计

在这之前我们先介绍一个特殊的值,memory.limit_in_bytes 这个可能是我们接触最多的参数,用于进程 物理内存资源限制

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat /sys/fs/cgroup/memory/user.slice/user-1000.slice/session-1.scope/memory.limit_in_bytes
9223372036854771712

可以看到上面的 htop, 文件中的值 9223372036854771712 表示当前 cgroup 的内存限制处于​​无限制状态​​,当 cgroup 未显式设置内存限制时,内核会默认将此值设为 PAGE_COUNTER_MAX,该值由内核通过 LONG_MAX / PAGE_SIZE * PAGE_SIZE 计算得出,确保与内存页对齐.

memory.stat

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat /sys/fs/cgroup/memory/user.slice/user-1000.slice/session-1.scope/memory.stat 
cache 393973760
rss 301170688
rss_huge 171966464
shmem 847872
mapped_file 86605824
dirty 8192
writeback 0
swap 0
pgpgin 241505
pgpgout 113977
pgfault 231305
pgmajfault 260
inactive_anon 302727168
active_anon 147456
inactive_file 348233728
active_file 44892160
unevictable 0
hierarchical_memory_limit 9223372036854771712
hierarchical_memsw_limit 9223372036854771712
total_cache 393973760
total_rss 301170688
total_rss_huge 171966464
total_shmem 847872
total_mapped_file 86605824
total_dirty 8192
total_writeback 0
total_swap 0
total_pgpgin 241505
total_pgpgout 113977
total_pgfault 231305
total_pgmajfault 260
total_inactive_anon 302727168
total_active_anon 147456
total_inactive_file 348233728
total_active_file 44892160
total_unevictable 0
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$

以下是关键参数的说明


memory.stat 核心参数解析表

参数分类 参数名 值(字节) 说明 相关引用
基础内存使用 cache 393,973,760 文件缓存和 tmpfs/shmem 内存,用于加速文件访问(可回收)
rss 301,170,688 进程匿名内存(堆、栈等)占用,反映实际物理内存使用量
swap 0 当前 cgroup 使用的交换空间大小,非零表示物理内存不足
内存页管理 active_anon 147,456 活跃的匿名内存页(正在使用的堆、栈内存)
inactive_anon 302,727,168 非活跃的匿名内存页(可被回收的堆、栈内存)
active_file 44,892,160 活跃的文件缓存页(近期被频繁访问的文件数据)
inactive_file 348,233,728 非活跃的文件缓存页(长时间未访问的文件数据,优先回收)
内存事件 pgpgin 241,505 从磁盘换入内存的页数,高值可能反映频繁 I/O
pgpgout 113,977 从内存换出到磁盘的页数
pgmajfault 260 需磁盘 I/O 的硬缺页次数,高值可能引发性能问题
层级管理 hierarchical_memory_limit 9,223,372,036... 层级化内存限制(当前值为极大数,表示未启用限制)
total_* 系列(如 total_rss) 与同名参数一致 包含当前 cgroup 及其子 cgroup 的总统计值(如 total_rss 表示层级内所有进程的匿名内存总和)
其他 rss_huge 171,966,464 透明大页(THP)占用量,大页可减少内存管理开销
unevictable 0 不可回收的内存(如 mlock 锁定的内存)

  1. 单位与换算:上述值均为 字节(Bytes),可通过 1 GB = 1073741824 Bytes 转换为更易读的单位。例如: • cache = 393,973,760 Bytes ≈ 376 MB • rss = 301,170,688 Bytes ≈ 287 MB
  2. 关键场景判断: • 内存压力:若 rss 接近 hierarchical_memory_limit,需警惕 OOM(内存耗尽)风险。 • 缓存优化:若 inactive_file 较高,可通过 sync; echo 3 > /proc/sys/vm/drop_caches 手动回收缓存。
  3. 与 free/vmstat 的关系: • free -m 中的 buff/cache 对应 cache + buff(部分系统可能合并统计)。 • vmstat 的 si/so 对应 pgpgin/pgpgout 的实时动态变化。

如需进一步分析具体进程的内存行为,可结合 /proc/<PID>/smaps 或工具如 smem。

memory.numa_stat

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat /sys/fs/cgroup/memory/user.slice/user-1000.slice/session-1.scope/memory.numa_stat 
total=169929 N0=169929
file=95978 N0=95978
anon=73951 N0=73951
unevictable=0 N0=0
hierarchical_total=169929 N0=169929
hierarchical_file=95978 N0=95978
hierarchical_anon=73951 N0=73951
hierarchical_unevictable=0 N0=0
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$

以下是对 memory.numa_stat 输出参数的详细解释

参数名 类型 描述
total 基础统计项 当前 cgroup 在 NUMA 节点上的总内存占用(单位字节),等于 anon + file + unevictable 之和
file 基础统计项 文件页缓存(File-backed memory)占用量,例如程序文件、共享库等通过文件映射的内存
anon 基础统计项 匿名页(Anonymous pages)和 Swap 缓存的总量,例如堆、栈等动态分配的内存
unevictable 基础统计项 不可回收的内存页(例如被锁定或标记为不可回收的页面)
hierarchical_total 层级统计项 包含所有子 cgroup 的总内存占用(单位字节),统计范围覆盖当前 cgroup 及其子级
hierarchical_file 层级统计项 包含所有子 cgroup 的文件页缓存总量
hierarchical_anon 层级统计项 包含所有子 cgroup 的匿名页和 Swap 缓存总量
hierarchical_unevictable 层级统计项 包含所有子 cgroup 的不可回收内存总量

补充说明:

  1. NUMA 节点标识:输出中的 N0=169929 表示当前统计值属于 NUMA 节点 0(N0)。在 NUMA 架构中,每个节点的本地内存访问速度更快,跨节点访问会增加延迟。
  2. 层级统计的意义: 带 hierarchical_ 前缀的参数表示当前 cgroup 及其所有子 cgroup 的累积内存使用量。例如,hierarchical_total 是当前 cgroup 和子 cgroup 在所有 NUMA 节点上的内存总量。
  3. 应用场景:通过对比 total 和 hierarchical_total,可判断子 cgroup 的内存分配是否合理。若 unevictable 值较高,可能需排查是否有进程误用内存锁定(如 mlock)。

上面的输出信息中提供的输出中,total=169929 N0=169929 表示该 cgroup 仅在 NUMA 节点 0 上分配了 169,929 字节内存。其中:

• 文件页缓存占 95,978 字节(file=95978),
• 匿名页和 Swap 缓存占 73,951 字节(anon=73951),
• 无不可回收内存(unevictable=0)。

内存事件指标监控

下面为内存事件指标依次来看一下

参数 作用
memory.usage_in_bytes 当前物理内存使用量(包括匿名内存、文件缓存等)。
memory.memsw.usage_in_bytes 当前物理内存 + swap 总使用量。
memory.failcnt 记录内存限制触发的失败次数(超出 memory.limit_in_bytes 的次数)。
memory.events 内存事件计数器(如 oom 溢出次数、under_oom 低内存状态)。
memory.events.local 同上,但仅统计当前 cgroup(不包含子 cgroup)。

这里我们使用 tuned 这个服务,这是一个系统调优的服务,作为一个独立的 service unit 存在,所以会有一个单独 Cgroup 分组

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$pgrep tuned
3654
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$ps -o cgroup 3654
CGROUP
11:pids:/system.slice/tuned.service,
8:memory:/system.slice/tuned.service,
2:devices:/system.slice/tuned.service,
1:name=systemd:/system.slice/tuned.service
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$

可以在 Cgroup 路径下面看到所有的指标数据 /sys/fs/cgroup/memory/system.slice/tuned.service/,还有部分内核相关的,这里我们只看一下内存相关的

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat /sys/fs/cgroup/memory/system.slice/tuned.service/
cgroup.clone_children               memory.kmem.limit_in_bytes          memory.max_usage_in_bytes           memory.pressure_level
cgroup.event_control                memory.kmem.max_usage_in_bytes      memory.memfs_files_info             memory.qos_level
cgroup.kill                         memory.kmem.slabinfo                memory.memsw.failcnt                memory.soft_limit_in_bytes
cgroup.procs                        memory.kmem.tcp.failcnt             memory.memsw.limit_in_bytes         memory.stat
memory.events                       memory.kmem.tcp.limit_in_bytes      memory.memsw.max_usage_in_bytes     memory.swappiness
memory.events.local                 memory.kmem.tcp.max_usage_in_bytes  memory.memsw.usage_in_bytes         memory.usage_in_bytes
memory.failcnt                      memory.kmem.tcp.usage_in_bytes      memory.min                          memory.use_hierarchy
memory.force_empty                  memory.kmem.usage_in_bytes          memory.move_charge_at_immigrate     notify_on_release
memory.high                         memory.limit_in_bytes               memory.numa_stat                    tasks
memory.kmem.failcnt                 memory.low                          memory.oom_control

​​memory.usage_in_bytes​ : 当前 cgroup 中所有进程实际使用的物理内存总量(包括 RSS 和 Page Cache),单位字节(约 15.86 MB)。

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat /sys/fs/cgroup/memory/system.slice/tuned.service/memory.usage_in_bytes 
16629760

​​memory.memsw.usage_in_bytes​ : 当前 cgroup 中所有进程使用的物理内存 + Swap 空间的总量(单位字节)。此处与物理内存相等,说明未使用 Swap。

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat /sys/fs/cgroup/memory/system.slice/tuned.service/memory.memsw.usage_in_bytes
16629760

memory.failcnt 存使用达到 memory.limit_in_bytes 设定的限制值的次数。值为 0 表示未触发过内存超限。

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat /sys/fs/cgroup/memory/system.slice/tuned.service/memory.failcnt
0

memory.events 内存事件计数器:

  • low: 低内存压力事件次数
  • high: 高内存压力事件次数
  • limit_in_bytes: 达到内存限制的次数
  • oom: OOM(内存耗尽)触发次数。全为 0 表示无相关事件发生。
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat /sys/fs/cgroup/memory/system.slice/tuned.service/memory.events
low 0
high 0
limit_in_bytes 0
oom 0
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$

当然还有一些其他的参数,感兴小伙伴可以研究下,通过去读上面的参数可以进行性能分析,系统监控

proc 内存伪文件系统

如果需要详细查看一个进程使用了哪些虚拟地址,可用使用 pmap PID 命令或者基于 proc 内存伪文件系统查看内存详细信息,比如 /proc/1/status,/proc/PID/maps 和/proc/PID/smaps等,

查看进程详细内存段数据

pmap 1002

快速查看进程的虚拟内存布局和总占用。

┌──[root@liruilongs.github.io]-[~]
└─$pmap 1002
1002:   /usr/bin/python3 -Es /usr/sbin/tuned -l -P
0000561ae3586000      4K r---- python3.9 # 文件路径
0000561ae3587000      4K r-x-- python3.9
0000561ae3588000      4K r---- python3.9
0000561ae3589000      4K r---- python3.9
。。。。。。。。。。。。。。。。
00007ffc6f79b000    132K rw---   [ stack ] #进程栈。
00007ffc6f7ce000     16K r----   [ anon ] #匿名内存(堆、栈等)
00007ffc6f7d2000      8K r-x--   [ anon ]
ffffffffff600000      4K --x--   [ anon ]
 total           256364K
┌──[root@liruilongs.github.io]-[~]
└─$

对应的列分别表示:内存段的起始虚拟地址(如 0000561ae3586000)。内存段的大小(如 4K)。内存访问权限 (r)可读 |(w)可写 |(x)可执行 |(s)共享 |(p)私有

/proc/1/maps

详细列出所有内存段的地址范围、权限和映射文件

┌──[root@liruilongs.github.io]-[~]
└─$cat /proc/1/maps | head -20
55e05a46b000-55e05a471000 r--p 00000000 fd:00 372298                     /usr/lib/systemd/systemd
55e05a471000-55e05a47c000 r-xp 00006000 fd:00 372298                     /usr/lib/systemd/systemd
55e05a47c000-55e05a481000 r--p 00011000 fd:00 372298                     /usr/lib/systemd/systemd
55e05a482000-55e05a483000 r--p 00016000 fd:00 372298                     /usr/lib/systemd/systemd
55e05a483000-55e05a484000 rw-p 00017000 fd:00 372298                     /usr/lib/systemd/systemd
55e05af99000-55e05b2a3000 rw-p 00000000 00:00 0                          [heap]
7ff43c000000-7ff43c021000 rw-p 00000000 00:00 0
7ff43c021000-7ff440000000 ---p 00000000 00:00 0
7ff444000000-7ff444021000 rw-p 00000000 00:00 0
7ff444021000-7ff448000000 ---p 00000000 00:00 0
7ff44b761000-7ff44b762000 ---p 00000000 00:00 0
7ff44b762000-7ff44bf62000 rw-p 00000000 00:00 0
7ff44bf62000-7ff44bf63000 ---p 00000000 00:00 0
7ff44bf63000-7ff44c766000 rw-p 00000000 00:00 0
7ff44c766000-7ff44c768000 r--p 00000000 fd:00 33948825                   /usr/lib64/libffi.so.8.1.0
7ff44c768000-7ff44c76e000 r-xp 00002000 fd:00 33948825                   /usr/lib64/libffi.so.8.1.0
7ff44c76e000-7ff44c76f000 r--p 00008000 fd:00 33948825                   /usr/lib64/libffi.so.8.1.0
7ff44c76f000-7ff44c770000 ---p 00009000 fd:00 33948825                   /usr/lib64/libffi.so.8.1.0
7ff44c770000-7ff44c771000 r--p 00009000 fd:00 33948825                   /usr/lib64/libffi.so.8.1.0
7ff44c771000-7ff44c772000 rw-p 0000a000 fd:00 33948825                   /usr/lib64/libffi.so.8.1.0

可以看到在上面的基础上,展示了内存段的起始和结束虚拟地址(如 55e05a46b000-55e05a471000)。多了映射文件在文件中的偏移量(十六进制,如 00000000)。文件所在设备的编号(格式 fd:00,主设备号:次设备号)。文件的 inode 编号(如 372298)。

/proc/1/smaps

提供每个内存段的详细物理内存统计(RSS、PSS、共享/私有内存等)

┌──[root@liruilongs.github.io]-[~]
└─$cat /proc/1/smaps | head -30
55e05a46b000-55e05a471000 r--p 00000000 fd:00 372298                     /usr/lib/systemd/systemd
Size:                 24 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Rss:                  24 kB
Pss:                   7 kB
Shared_Clean:         24 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:         0 kB
Referenced:           24 kB
Anonymous:             0 kB
LazyFree:              0 kB
AnonHugePages:         0 kB
ShmemPmdMapped:        0 kB
FilePmdMapped:         0 kB
Shared_Hugetlb:        0 kB
Private_Hugetlb:       0 kB
Swap:                  0 kB
SwapPss:               0 kB
Locked:                0 kB
THPeligible:    0
VmFlags: rd mr mw me sd
55e05a471000-55e05a47c000 r-xp 00006000 fd:00 372298                     /usr/lib/systemd/systemd
Size:                 44 kB
KernelPageSize:        4 kB
┌──[root@liruilongs.github.io]-[~]
└─$

部分字段说明​​:

  • Size​:​ 内存段的虚拟大小(如 24 kB)。
  • ​​Rss:(Resident Set Size)​​ 实际占用的物理内存(包含共享内存)。
  • ​​Pss:(Proportional Set Size)​​ 按共享比例计算的物理内存(如 3 个进程共享 24KB → 每个进程 Pss 8KB)。
  • ​​Shared_Clean/Shared_Dirty:​​ 共享内存中未修改/已修改的部分。
  • ​​Private_Clean/Private_Dirty:​​ 私有内存中未修改/已修改的部分。
  • ​​Swap​:​ 被交换到磁盘的内存大小。
  • ​​VmFlags​:​ 内存段的属性标志(如 rd 可读,mr 可映射,mw 可写等)。

进程全局内存数据统计

status 用于展示当前进程的一些基本指标,进程基础信息,权限与身份​​,信号与中断​等

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat  /proc/1/status 
Name: systemd
Umask: 0000
State: S (sleeping)
Tgid: 1
Ngid: 0
Pid: 1
PPid: 0
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 256
Groups:  
NStgid: 1
NSpid: 1
NSpgid: 1
NSsid: 1
VmPeak:   165112 kB
VmSize:   100636 kB
VmLck:        0 kB
VmPin:        0 kB
VmHWM:    12688 kB
VmRSS:    12688 kB
RssAnon:     4084 kB
RssFile:     8604 kB
RssShmem:        0 kB
VmData:    19052 kB
VmStk:     1036 kB
VmExe:      884 kB
VmLib:     8832 kB
VmPTE:       84 kB
VmSwap:        0 kB
HugetlbPages:        0 kB
CoreDumping: 0
THP_enabled: 1
Threads: 1
SigQ: 0/29616
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 7be3c0fe28014a03
SigIgn: 0000000000001000
SigCgt: 00000001000004ec
CapInh: 0000000000000000
CapPrm: 000001ffffffffff
CapEff: 000001ffffffffff
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000
NoNewPrivs: 0
Seccomp: 0
Seccomp_filters: 0
Speculation_Store_Bypass: thread vulnerable
Cpus_allowed: f
Cpus_allowed_list: 0-3
Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 2558
nonvoluntary_ctxt_switches: 483

这里只关注内存相关的

虚拟内存核心指标

参数 值 描述
VmPeak 165,112 kB 进程生命周期内虚拟内存的 峰值(含已分配但未使用的内存),反映进程曾达到的最大内存需求
VmSize 100,636 kB 当前进程 虚拟地址空间总大小(包括代码、数据、堆、栈等所有映射区域),约 98.27 MB

物理内存核心指标

参数 值 描述
VmHWM 12,688 kB 进程物理内存使用 峰值(Resident Set Size 最大值),约 12.38 MB
VmRSS 12,688 kB 当前实际驻留物理内存(RSS),等于 RssAnon + RssFile + RssShmem,约 12.38 MB
RssAnon 4,084 kB 匿名页(动态分配的堆/栈内存)占用的物理内存,例如 malloc 分配的未映射文件的内存
RssFile 8,604 kB 文件页缓存占用的物理内存(如加载的共享库、内存映射文件)
RssShmem 0 kB 共享内存段(如 shmget 创建的 IPC 内存)占用的物理内存

内存区域细分指标

参数 值 描述
VmData 19,052 kB 数据段 + 堆 的虚拟内存大小(动态分配的内存通过 brk 或 mmap 扩展)
VmStk 1,036 kB 栈空间 的虚拟内存大小(存放局部变量和函数调用帧),默认上限由 ulimit -s 控制
VmExe 884 kB 可执行代码段 的虚拟内存大小(程序本身的机器指令,只读)
VmLib 8,832 kB 共享库 的虚拟内存大小(如 glibc 等动态链接库)

其他关键参数

参数 值 描述
VmLck 0 kB 锁定的物理内存(通过 mlock 系统调用防止被换出到 Swap),常用于实时性要求高的场景
VmPTE 84 kB 页表项 占用的物理内存(用于管理虚拟地址到物理地址的映射关系)
VmSwap 0 kB 当前已换出到 Swap 分区 的内存大小(若值持续增长,需排查内存泄漏或物理内存不足)

关键应用场景分析

内存泄漏检测

  • 对比 VmSize 和 VmRSS:若 VmSize 持续增长而 VmRSS 稳定,可能为虚拟内存分配过多但未实际使用(如未初始化的 malloc)。
  • 监控 VmSwap:若长期非零,需检查物理内存是否不足或进程存在内存滥用。

性能优化方向

  • 共享库优化:VmLib 值较高时,可考虑静态链接或减少动态库依赖以降低内存开销。
  • 堆栈管理:VmData 和 VmStk 异常增长可能提示堆内存泄漏或递归调用过深。

系统资源分配

  • VmHWM 可用于设置 CGroup 内存限制(memory.max_usage_in_bytes),避免单个进程耗尽物理内存。
  • RssFile 较高时,可通过清理缓存(sync; echo 1 > /proc/sys/vm/drop_caches)释放非关键文件缓存。

statm 用于展示进程内存快照,但需注意 单位是内存页,通常 1 页 = 4 KB

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat  /proc/1/statm
25159 3172 2151 221 0 5022 0

字段解析

参数 值 描述 换算为 KB
size 25159 进程虚拟地址空间总大小(含代码、数据、堆栈等所有映射区域) 25159 × 4 ≈ 100,636 KB
Resident 3172 实际驻留物理内存(RSS),即当前进程使用的物理内存总量 3172 × 4 ≈ 12,688 KB
Shared 2151 共享内存页数(如动态链接库、共享内存段等被多个进程共享的部分) 2151 × 4 ≈ 8,604 KB
Trs 221 可执行代码段(Text Resident Set)占用的内存页(如程序自身的机器指令) 221 × 4 ≈ 884 KB
Lrs 0 库的内存页数(Linux 2.6+ 中已废弃,通常为 0) -
Drs 5022 数据段(堆、全局变量)和用户态栈的总内存页 5022 × 4 ≈ 20,088 KB
dt 0 脏页数量(已修改但未写入磁盘的页,Linux 2.6+ 中已废弃) -

与 /proc/1/status 的关联 对比 /proc/1/status 中的内存参数可验证数据一致性

• VmSize: 100636 kB = size × 4 = 25159 × 4
• VmRSS: 12688 kB = Resident × 4 = 3172 × 4
• RssFile: 8604 kB ≈ Shared × 4 = 2151 × 4
• VmExe: 884 kB = Trs × 4 = 221 × 4
• VmData + VmStk: 19052 + 1036 = 20088 kB ≈ Drs × 4 = 5022 × 4

smaps_rollup 提供进程 ​​全局汇总统计​​(如总 RSS、PSS、Swap 等), 读取 smaps_rollup 比遍历 smaps 更高效(减少锁竞争时间),适合高频监控场景,

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat  /proc/1/smaps_rollup 
56476fafe000-7ffc5b7f8000 ---p 00000000 00:00 0                          [rollup]
Rss:               12692 kB
Pss:                4648 kB
Pss_Anon:           3463 kB
Pss_File:           1184 kB
Pss_Shmem:             0 kB
Shared_Clean:       8540 kB
Shared_Dirty:        936 kB
Private_Clean:        64 kB
Private_Dirty:      3152 kB
Referenced:        12692 kB
Anonymous:          4088 kB
LazyFree:              0 kB
AnonHugePages:         0 kB
ShmemPmdMapped:        0 kB
FilePmdMapped:         0 kB
Shared_Hugetlb:        0 kB
Private_Hugetlb:       0 kB
Swap:                  0 kB
SwapPss:               0 kB
Locked:                0 kB

核心内存统计

参数 值 描述
Rss 12,692 kB 常驻物理内存总量(包含共享和私有内存),等于 Shared_Clean + Shared_Dirty + Private_Clean + Private_Dirty
Pss 4,648 kB 比例集内存(按共享比例分摊后的内存),Pss = Pss_Anon + Pss_File + Pss_Shmem
Pss_Anon 3,463 kB 匿名页(如堆、栈)分摊后的内存,反映独占或部分共享的匿名内存
Pss_File 1,184 kB 文件页缓存(如共享库、映射文件)分摊后的内存
Pss_Shmem 0 kB 共享内存(如 tmpfs)的分摊内存,此处未使用

共享与私有内存分布

参数 值 描述
Shared_Clean 8,540 kB 共享的未修改内存(如只读共享库),可被内核直接回收
Shared_Dirty 936 kB 共享的已修改内存(如被多个进程写入的共享内存),需同步到磁盘后才能回收
Private_Clean 64 kB 私有的未修改内存(如未修改的私有数据),可快速回收
Private_Dirty 3,152 kB 私有的已修改内存(如进程堆内存),需写入 Swap 或文件后才能回收

其他关键参数

参数 值 描述
Anonymous 4,088 kB 匿名内存总量(无法关联文件的内存,如 malloc 分配的内存)
Swap 0 kB 已换出到 Swap 分区的内存量,此处为 0 表示未启用 Swap 或内存充足
Locked 0 kB 通过 mlock 锁定的内存(不可被换出),常用于实时性要求高的场景
Referenced 12,692 kB 最近被访问过的内存页,反映当前活跃内存

这是两个 OOM 内存杀手相关的,这里不多讲,在之后的博客中会和小伙伴分享

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat  /proc/1/oom_score
0
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$cat  /proc/1/oom_score_adj 
0

博文部分内容参考

© 文中涉及参考链接内容版权归原作者所有,如有侵权请告知 :)


《 Red Hat Performance Tuning 442 》

《性能之巅 系统、企业与云可观测性(第2版)》


© 2018-至今 liruilonger@gmail.com, 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。