Linux 进程内存监控:Linux 内存调优之进程内存深度监控
写在前面
-
博文内容涉及 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 锁定的内存) |
-
单位与换算:上述值均为 字节(Bytes),可通过 1 GB = 1073741824 Bytes
转换为更易读的单位。例如: •cache = 393,973,760 Bytes ≈ 376 MB
•rss = 301,170,688 Bytes ≈ 287 MB
-
关键场景判断: • 内存压力:若 rss
接近hierarchical_memory_limit
,需警惕 OOM(内存耗尽)风险。 • 缓存优化:若inactive_file
较高,可通过sync; echo 3 > /proc/sys/vm/drop_caches
手动回收缓存。 -
与 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 的不可回收内存总量 |
补充说明:
-
NUMA 节点标识:输出中的 N0=169929
表示当前统计值属于 NUMA 节点 0(N0
)。在 NUMA 架构中,每个节点的本地内存访问速度更快,跨节点访问会增加延迟。 -
层级统计的意义: 带 hierarchical_
前缀的参数表示当前 cgroup 及其所有子 cgroup 的累积内存使用量。例如,hierarchical_total
是当前 cgroup 和子 cgroup 在所有 NUMA 节点上的内存总量。 -
应用场景:通过对比 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)
- 点赞
- 收藏
- 关注作者
评论(0)