操作系统基础 | 内存分析工具
内存分析工具主要包含日常常用工具、systemtap和bpftrace工具等。其中常用工具主要包括:vmstat、wapon、sar、slabtop、numastat、ps、top、pmap等。
内存分析常用工具
vmstat
vmstat是一个虚拟内存统计工具,提供了一个上层视角的内存监控状态,包含空闲内存和换页统计;其中cpu相关的参数在之前已经讲解过。
~# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 574936 155544 6819876 0 0 0 1 0 0 0 0 100 0 0
0 0 0 574888 155544 6819964 0 0 0 0 102 100 0 0 100 0 0
0 0 0 595600 155544 6819964 0 0 0 0 185 161 0 1 99 0 0
0 0 0 596136 155544 6819964 0 0 0 0 116 101 0 0 100 0 0
0 0 0 596192 155552 6819964 0 0 0 56 155 217 0 0 100 0 0
0 0 0 596160 155552 6819964 0 0 0 0 114 109 0 0 100 0 0
0 0 0 596192 155552 6819964 0 0 0 0 101 89 0 0 100 0 0
命令输出的第一行不是系统从启动到现在的数据,而是当前时刻的数据。以下列的默认值是kilobytes:
- swpd:换出内存的总量
- free:空闲内存的总量
- buff:buffer缓存的内存总量
- cache:页缓存的内存总量
- si:换入内存总量(换页paging)
- so:换出内存总量(换页paging)
如果感觉输出的格式后面比较乱,对不齐,可以使用-S参数进行格式输出(M代表1024进制MB,m代表1000进制MB),如下所示。
1024进制
~# vmstat -SM 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 582 151 6660 0 0 0 1 0 0 0 0 100 0 0
0 0 0 582 151 6660 0 0 0 0 86 73 0 0 100 0 0
0 0 0 582 151 6660 0 0 0 0 54 66 0 0 100 0 0
0 0 0 582 151 6660 0 0 0 0 74 81 0 0 100 0 0
0 0 0 582 151 6660 0 0 0 0 51 61 0 0 100 0 0
0 0 0 582 151 6660 0 0 0 0 42 45 0 0 100 0 0
1000进制
~# vmstat -Sm 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 610 159 6983 0 0 0 1 0 0 0 0 100 0 0
0 0 0 610 159 6983 0 0 0 0 90 96 0 0 100 0 0
0 0 0 610 159 6983 0 0 0 0 70 71 0 0 100 0 0
0 0 0 610 159 6983 0 0 0 0 51 61 0 0 100 0 0
0 0 0 610 159 6983 0 0 0 0 101 111 0 0 100 0 0
0 0 0 610 159 6983 0 0 0 0 77 87 0 0 100 0 0
可以使用-a参数显示页缓存中活跃或非活跃的内存。
~# vmstat -a -SM 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free inact active si so bi bo in cs us sy id wa st
1 0 0 582 4172 2133 0 0 0 1 0 0 0 0 100 0 0
0 0 0 582 4172 2133 0 0 0 0 84 83 0 0 100 0 0
0 0 0 582 4172 2133 0 0 0 0 73 81 0 0 100 0 0
0 0 0 582 4172 2133 0 0 0 0 89 108 0 0 100 0 0
0 0 0 582 4172 2133 0 0 0 0 82 85 0 0 100 0 0
0 0 0 582 4172 2133 0 0 0 0 71 79 0 0 100 0 0
可以使用-s参数以列表形式打印内存使用统计。
~# vmstat -s
8147216 K total memory
574224 K used memory
2184904 K active memory
4272516 K inactive memory
597264 K free memory
155608 K buffer memory
6820120 K swap cache
0 K total swap
0 K used swap
0 K free swap
988896 non-nice user cpu ticks
160614 nice user cpu ticks
871224 system cpu ticks
9520067017 idle cpu ticks
164229 IO-wait cpu ticks
0 IRQ cpu ticks
243435 softirq cpu ticks
555064 stolen cpu ticks
3918760 pages paged in
64968211 pages paged out
0 pages swapped in
0 pages swapped out
1195009341 interrupts
1140494763 CPU context switches
1644926996 boot time
980686 forks
PSI
在4.20以后的内核版本中引入了PSI(pressure stall information),包含内存满载度的统计。不仅能显示内存压力,还能显示压力在过去5分钟的变化状态。
~# cat /proc/pressure/memory
some avg10=2.84 avg60=1.23 avg300=0.32 total=1468344
full avg10=1.85 avg60=0.66 avg300=0.16 total=702578
从结果中可以看出,内存的压力在逐渐增大。过去10秒的均值大于过去300秒的均值。值代表任务暂停在内存上面的时间占比。some一行显示某些被影响的进程(线程),full一行显示的是所有被影响的进程(线程)。
swapon
swapon命令可以用来查看交换设备是否被配置,如果被配置,则其输出结果会出现在vmstat命令中的si和so列,如果没有配置则命令没有任何输出。没有配置
~# swapon
~#
有配置
~# swapon
NAME TYPE SIZE USED PRIO
/dev/dm-2 partition 980M 611.6M -2
/swap1 file 30G 10.9M -3
free
free命令输出系统内存使用的整体结果,如下所示。
~# free
total used free shared buff/cache available
Mem: 8147216 574724 596612 7952 6975880 7260968
Swap: 0 0 0
低版本的centos可能输出的结果不太一样,但是大致是相同的,我们以centos7以后的结果为例讲解:
- total:系统总的物理内存和交换空间
- used:系统已经使用的物理内核和交换空间
- free:系统剩余物理内存和交换空间
- shard:被共享使用的物理内存大小,可以包含共享库和/dev/shm下的内容
- buff/cache:被buff和cache使用的内存大小
- available:还可以被系统使用的内存大小,是一个预测值,并非立即可用大小
可以使用-w参数将buff和cache分开显示,如下所示。
~# free -w
total used free shared buffers cache available
Mem: 8147216 575416 595828 7952 155744 6820228 7260288
Swap: 0 0 0
ps
ps命令可以显示进程使用的内存,如下所示。
~# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 172556 14572 ? Ss Feb15 4:09 /sbin/init
root 2 0.0 0.0 0 0 ? S Feb15 0:03 [kthreadd]
root 3 0.0 0.0 0 0 ? I< Feb15 0:00 [rcu_gp]
root 4 0.0 0.0 0 0 ? I< Feb15 0:00 [rcu_par_gp]
root 6 0.0 0.0 0 0 ? I< Feb15 0:00 [kworker/0:0H-kblockd]
root 9 0.0 0.0 0 0 ? I< Feb15 0:00 [mm_percpu_wq]
root 10 0.0 0.0 0 0 ? S Feb15 0:01 [ksoftirqd/0]
root 11 0.0 0.0 0 0 ? I Feb15 107:52 [rcu_sched]
其中需要注意的有以下3列:
- %MEM:进程使用系统物理内存的百分比
- VSZ:虚拟内存大小
- RSS:进程正在使用的所有物理内存
ps命令可以通过参数指定输出以上几列,更多信息可以查看/proc/<pid>/status。
~# ps -eo pid,pmem,vsz,rss | head -10
PID %MEM VSZ RSS
1 0.1 172556 14572
2 0.0 0 0
3 0.0 0 0
4 0.0 0 0
6 0.0 0 0
9 0.0 0 0
10 0.0 0 0
11 0.0 0 0
12 0.0 0 0
-x参数可以增加Dirty一列,将展示已经被修改但是还没写回的页。
slabtop
slabtop命令可以打印出内核slab分配器缓存的使用情况,与top类似,实时输出,例如。
~# slabtop -sc
Active / Total Objects (% used) : 3682298 / 4152088 (88.7%)
Active / Total Objects (% used) : 3682337 / 4152127 (88.7%)
Active / Total Slabs (% used) : 116386 / 116386 (100.0%)
Active / Total Caches (% used) : 104 / 157 (66.2%)
Active / Total Size (% used) : 845034.22K / 961201.15K (87.9%)
Minimum / Average / Maximum Object : 0.01K / 0.23K / 8.00K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
327265 286556 87% 1.07K 11285 29 361120K ext4_inode_cache
1484886 1370300 92% 0.10K 38074 39 152296K buffer_head
645351 438645 67% 0.19K 30731 21 122924K dentry
136668 114266 83% 0.57K 4881 28 78096K radix_tree_node
59228 57655 97% 0.59K 2278 26 36448K inode_cache
169080 168393 99% 0.13K 5636 30 22544K kernfs_node_cache
4176 4149 99% 4.00K 522 8 16704K kmalloc-4k
77493 76762 99% 0.20K 1987 39 15896K vm_area_struct
361794 328979 90% 0.04K 3547 102 14188K ext4_extent_status
199808 193039 96% 0.06K 3122 64 12488K vmap_area
47424 45219 95% 0.25K 1482 32 11856K filp
10336 10006 96% 1.00K 323 32 10336K kmalloc-1k
-sc参数是指定使用cache size进行排序,使用最多的排在上面。
slab统计信息来自/proc/slabinfo,也可以通过vmstat -m命令打印。
numastat
numastat可以打印在NUMA架构内存访问,以下是有2颗CPU的输出结果。
$ numastat
node0 node1
numa_hit 22803297317096 16241914532514
numa_miss 216025857428 7470170746474
numa_foreign 7470170746376 216025857426
interleave_hit 100698246 143800065
local_node 22803189089828 16242714785561
other_node 216134084696 7469370493427
numastat命令可以通过以下命令安装yum install numactl。关键信息如下:
- numa_hit:内存分配在local节点
- numa_miss+numa_foregin:内存分配在非优先选择的节点
- other_node:内存分配在这个节点,但是进程运行在另外一个节点。
top
top命令会显示正在运行的程序和程序使用的内存信息。如下所示。
~# top -o %MEM
top - 17:28:45 up 1262 days, 5:55, 1 user, load average: 98.05, 91.25, 93.78
Tasks: 2364 total, 6 running, 2356 sleeping, 0 stopped, 2 zombie
%Cpu(s): 71.8 us, 8.0 sy, 0.0 ni, 11.6 id, 7.6 wa, 0.0 hi, 1.0 si, 0.0 st
KiB Mem : 19780201+total, 4733848 free, 14077816+used, 52290016 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 48779544 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
10893 yarn 20 0 12.590g 0.010t 14008 S 420.0 5.5 68:55.24 java
154889 yarn 20 0 14.960g 0.010t 15396 S 625.0 5.3 18847:13 java
186790 yarn 20 0 14.960g 0.010t 15396 R 10.0 5.3 0:00.02 java
156061 yarn 20 0 10.996g 9.143g 13600 S 5.0 4.8 787:21.09 java
117171 yarn 20 0 10.399g 8.717g 13564 S 0.0 4.6 655:34.94 java
193316 yarn 20 0 10.840g 8.668g 13508 S 0.0 4.6 33:14.55 java
输出结果中,通过-o %MEM参数对输出结果按照内存使用量大小进行了逆序排序。
sar
sar(system activity reporter),可以用来观测当前系统的活动。Linux版本用来进行内存观测的参数如下:
- -B:换页统计
- -H:大页统计
- -r:内存使用率
- -S:交换分区统计
- -W:swapping统计
各项统计信息说明:
选项 | 统计 | 描述 | 单位 |
-B | pgpgin/s | 换入 | Kbytes/s |
pgpgout/s | 换出 | Kbytes/s | |
fault/s | major fault和minor fault | Count/s | |
majflt/s | major fault | Count/s | |
pgfree/s | 加到free list的页数量 | Count/s | |
pgscank/s | kwapd进程后台扫描的页数量 | Count/s | |
pgscand/s | 直接扫描的页数量 | Count/s | |
pgsteal/s | 页和交换缓存回收数 | Count/s | |
%vmeff | pg steal/pg scan的占比,可以反应页回收的效率 | Percent | |
-H | kbhugfree | 空闲大页内存 | Kbytes |
kbhugused | 大页使用量 | Kbytes | |
%hugused | 大页使用比例 | Percent | |
-r | kbmemfree | 空闲内存 | Kbytes |
kbmemused | 内存使用大小(不包含内核) | Kbytes | |
%memused | 内存使用率 | Percent | |
kbbuffers | Buffer cache大小 | Kbytes | |
kbcached | Page cache大小 | Kbytes | |
kbcommit | |||
%commit | |||
kbactive | Active list内存大小 | Kbytes | |
kbinact | Inactive list内存大小 | Kbytes | |
kbdirty | 需要写回磁盘的脏内存大小 | Kbytes | |
-S | kbswpfree | 空闲swap空间 | Kbytes |
kbswpused | 使用swap空间 | Kbytes | |
%swpused | 使用swap比例 | Percent | |
kbswpcad | cache的swap空间 | Kbytes | |
%swpcad | cache的swap空间占已使用的比例 | Percent | |
-W | pswpin/s | swap换入页数量 | Pages/s |
pswpout/s | swap换出页数量 | Pages/s |
sar -B
# sar -B 1
Linux 3.10.0-693.5.2.el7.x86_64 (xxxxxxx) 07/04/2022 _x86_64_ (56 CPU)
07:44:31 PM pgpgin/s pgpgout/s fault/s majflt/s pgfree/s pgscank/s pgscand/s pgsteal/s %vmeff
07:44:32 PM 8232.00 0.00 448092.00 0.00 35553.00 0.00 0.00 0.00 0.00
07:44:33 PM 24068.00 208.00 508789.00 0.00 35398.00 0.00 0.00 0.00 0.00
07:44:34 PM 140120.00 43032.00 838535.00 0.00 52782.00 0.00 0.00 0.00 0.00
07:44:35 PM 182600.00 8600.00 780663.00 0.00 69181.00 0.00 0.00 0.00 0.00
07:44:36 PM 96316.00 224.00 538031.00 0.00 41329.00 0.00 0.00 0.00 0.00
07:44:37 PM 8276.00 732.00 575471.00 0.00 38922.00 0.00 0.00 0.00 0.00
07:44:38 PM 16172.00 24128.00 450544.00 0.00 49388.00 0.00 0.00 0.00 0.00
07:44:39 PM 8336.00 96.00 716726.00 0.00 36242.00 0.00 0.00 0.00 0.00
07:44:40 PM 8340.00 76.00 637336.00 0.00 60962.00 0.00 0.00 0.00 0.00
^C
07:44:41 PM 49796.92 467.69 591041.54 0.00 42863.08 0.00 0.00 0.00 0.00
Average: 54386.32 8020.73 609156.89 0.00 46385.28 0.00 0.00 0.00 0.00
sar -H
# sar -H 1
Linux 3.10.0-693.5.2.el7.x86_64 (xxxxxxx) 07/04/2022 _x86_64_ (56 CPU)
07:45:22 PM kbhugfree kbhugused %hugused
07:45:23 PM 0 0 0.00
07:45:24 PM 0 0 0.00
07:45:25 PM 0 0 0.00
07:45:26 PM 0 0 0.00
^C
07:45:27 PM 0 0 0.00
Average: 0 0 0.00
sar -r
# sar -r 1
Linux 3.10.0-693.5.2.el7.x86_64 (xxxxxxx) 07/04/2022 _x86_64_ (56 CPU)
07:45:57 PM kbmemfree kbmemused %memused kbbuffers kbcached kbcommit %commit kbactive kbinact kbdirty
07:45:58 PM 13626744 184165092 93.11 65460 60734772 136710732 69.12 131185828 48408768 38588
07:45:59 PM 13560152 184231684 93.14 65460 60790900 136710332 69.12 131189220 48465552 34664
07:46:00 PM 13518588 184273248 93.17 65460 60805216 136753604 69.14 131207576 48479612 48208
07:46:01 PM 13416536 184375300 93.22 65468 60813200 139314084 70.43 131274552 48486932 48676
07:46:02 PM 12874604 184917232 93.49 65476 60857060 169497468 85.69 131738296 48534912 31128
07:46:03 PM 12867388 184924448 93.49 65476 60854772 139385412 70.47 131804308 48533416 30860
07:46:04 PM 12623376 185168460 93.62 65476 60844268 141125696 71.35 132056892 48523128 32892
^C
07:46:04 PM 12651424 185140412 93.60 65476 60845112 141102516 71.34 132028816 48523196 32988
Average: 13142352 184649484 93.36 65469 60818162 142574980 72.08 131560686 48494440 37250
sar -S
# sar -S 1
Linux 3.10.0-693.5.2.el7.x86_64 (xxxxxxx) 07/04/2022 _x86_64_ (56 CPU)
07:46:46 PM kbswpfree kbswpused %swpused kbswpcad %swpcad
07:46:47 PM 0 0 0.00 0 0.00
07:46:48 PM 0 0 0.00 0 0.00
07:46:49 PM 0 0 0.00 0 0.00
07:46:50 PM 0 0 0.00 0 0.00
07:46:51 PM 0 0 0.00 0 0.00
07:46:52 PM 0 0 0.00 0 0.00
^C
07:46:52 PM 0 0 0.00 0 0.00
Average: 0 0 0.00 0 0.00
sar -W
# sar -W 1
Linux 3.10.0-693.5.2.el7.x86_64 (xxxxxxx) 07/04/2022 _x86_64_ (56 CPU)
07:46:55 PM pswpin/s pswpout/s
07:46:56 PM 0.00 0.00
07:46:57 PM 0.00 0.00
07:46:58 PM 0.00 0.00
07:46:59 PM 0.00 0.00
07:47:00 PM 0.00 0.00
^C
07:47:01 PM 0.00 0.00
Average: 0.00 0.00
perf
perf是Linux下面一个非常强大的工具,我们之前在CPU的章节中已经介绍过perf有关的用法,本次我们只讲解perf在内存方面的使用。
perf 单行命令
- 记录10s 缺页异常的事件数据
perf record -e page-faults -a -g -- sleep 10
[ perf record: Woken up 114 times to write data ]
[ perf record: Captured and wrote 38.086 MB perf.data (178308 samples) ]
- 记录PID为23912进程10秒缺页异常,连带栈信息
# perf record -e page-faults -c 1 -p 23912 -g -- sleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.287 MB perf.data (129 samples) ]
# perf script
Failed to open /tmp/perf-23912.map, continuing without symbols
java 52494 109151486.674671: page-faults:
654e4b CollectedHeap::common_mem_allocate_init (/usr/java/jdk1.8.0_102/jre/lib/amd64/server/libjvm.so)
6433cc InstanceKlass::allocate_instance (/usr/java/jdk1.8.0_102/jre/lib/amd64/server/libjvm.so)
9b949e OptoRuntime::new_instance_C (/usr/java/jdk1.8.0_102/jre/lib/amd64/server/libjvm.so)
7f83b05fb685 [unknown] (/tmp/perf-23912.map)
- 记录brk系统调用
# perf record -e syscalls:sys_enter_brk -a -g -- sleep 60
- 追踪kwapd进程唤醒事件,使用Ctrl+C结束
# perf record -e vmscan:mm_vmscan_wakeup_kswapd -ag
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.694 MB perf.data ]
使用perf工具生成火焰图
# perf record -e page-faults -a -g -- sleep 10
# perf script --header > out.sshd.stacks
# git clone https://github.com/brendangregg/FlameGraph
# ./FlameGraph/stackcollapse-perf.pl < out.sshd.stacks | ./FlameGraph/flamegraph.pl --hash --bgcolor=green --count=pages --title="SSHD Page Fault Flame Graph" > sshd.out.svg