1. free
root@node02:~# free -m total used free shared buff/cache available
Mem: 3919 1194 1738 1 986 2446
Swap: 0 0 0
free 输出的是一个表格,其中的数值都默认以字节为单位。表格总共有两行六列,这两行分别是物理内存 Mem 和交换分区 Swap 的使用情况,而六列中,每列数据的含义分别为:
第一列,total 是总内存大小;
第二列,used 是已使用内存的大小,包含了共享内存;
第三列,free 是未使用内存的大小;
第四列,shared 是共享内存的大小;
第五列,buff/cache 是缓存和缓冲区的大小;
最后一列,available 是新进程可用内存的大小。
注意一下,最后一列的可用内存 available 。available 不仅包含未使用内存,还包括了可回收的缓存,所以一般会比未使用内存更大。不过,并不是所有缓存都可以回收,因为有些缓存可能正在使用中。
2.top
top - 14:36:39 up 4 days, 13:51, 4 users, load average: 0.15, 0.15, 0.10
Tasks: 186 total, 1 running, 105 sleeping, 0 stopped, 0 zombie
%Cpu(s): 2.0 us, 1.2 sy, 0.0 ni, 96.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 4013240 total, 1778100 free, 1223896 used, 1011244 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 2504420 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1 root 20 0 159908 6288 3732 S 5.6 0.2 5:13.78 systemd
与内存相关的有如下几个指标:
VIRT 是进程虚拟内存的大小,只要是进程申请过的内存,即便还没有真正分配物理内存,也会计算在内。
RES 是常驻内存的大小,也就是进程实际使用的物理内存大小,但不包括 Swap 和共享内存。
SHR 是共享内存的大小,比如与其他进程共同使用的共享内存、加载的动态链接库以及程序的代码段等。
%MEM 是进程使用物理内存占系统总内存的百分比。
除了要认识这些基本信息,在查看 top 输出时,你还要注意两点。
第一,虚拟内存通常并不会全部分配物理内存。从上面的输出,你可以发现每个进程的虚拟内存都比常驻内存大得多。
第二,共享内存 SHR 并不一定是共享的,比方说,程序的代码段、非共享的动态链接库,也都算在 SHR 里。当然,SHR 也包括了进程间真正共享的内存。所以在计算多个进程的内存使用时,不要把所有进程的 SHR 直接相加得出结果。
3.ps
root@node02:~# ps aux | head
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 159908 6288 ? Ss Jan22 5:13 /sbin/init auto automatic-ubiquity noprompt
指标解释如下:
USER:该进程的所有者(用户)。
在这个例子中,用户是 root。
PID:进程ID(Process ID)。
在这个例子中,进程ID是 1。
%CPU:进程占用的CPU百分比。
在这个例子中,CPU使用率为 0.0,表示该进程当前没有占用CPU资源。
%MEM:进程占用的物理内存百分比。
在这个例子中,物理内存使用率为 0.1%。
VSZ:进程的虚拟内存大小(以KB为单位)。
在这个例子中,虚拟内存大小为 159908 KB。
RSS:进程占用的物理内存大小(以KB为单位)。
在这个例子中,物理内存大小为 6288 KB。
TTY:终端类型。
在这个例子中,终端是 ?,表示没有关联到具体的终端。
STAT:进程状态。常见的状态包括:
S:休眠(Sleeping)
R:运行(Running)
Z:僵尸进程(Zombie)
D:不可中断的休眠状态(Uninterruptible sleep)
在这个例子中,状态是 Ss,表示是一个会话(session)的首个进程。
START:进程的启动时间。
在这个例子中,启动时间是 Jan22,表示进程是在1月22日启动的。
TIME:进程占用CPU的累计时间。
4.vmstat
root@node02:~# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----r b swpd free buff cache si so bi bo in cs us sy id wa st0 0 0 2732400 4668 363688 0 0 4 21 17 23 3 1 95 0 0
指标解释如下:
procs
r:表示处于运行队列中(正在运行或等待运行)的进程数。
b:表示处于不可中断睡眠状态的进程数。
memory
swpd:表示被换出到交换空间的内存大小(单位:KB)。
free:表示空闲内存大小(单位:KB)。
buff:表示用作缓冲区的内存大小(单位:KB)。
cache:表示用作缓存的内存大小(单位:KB)。
swap
si:表示每秒从磁盘读入交换区的数据量(单位:KB)。
so:表示每秒写入到磁盘的交换区数据量(单位:KB)。
I/O
bi:表示每秒从块设备读入的数据量(单位:块,一般为 512 字节)。
bo:表示每秒向块设备写入的数据量(单位:块,一般为 512 字节)。
system
in:表示每秒产生的中断数。
cs:表示每秒上下文切换的次数。
CPU
us:表示用户空间占用 CPU 时间的百分比。
sy:表示内核空间占用 CPU 时间的百分比。
id:表示空闲 CPU 时间的百分比。
wa:表示等待 I/O 的 CPU 时间百分比。
st:表示被虚拟机偷走的 CPU 时间的百分比。
Buffers 是对原始磁盘块的临时存储,也就是用来缓存磁盘的数据,通常不会特别大(20MB 左右)。这样,内核就可以把分散的写集中起来,统一优化磁盘的写入,比如可以把多次小的写合并成单次大的写等等。 Cached 是从磁盘读取文件的页缓存,也就是用来缓存从文件读取的数据。这样,下次访问这些文件数据时,就可以直接从内存中快速获取,而不需要再次访问缓慢的磁盘。
简单理解:Buffer 是对磁盘数据的缓存,而 Cache 是文件数据的缓存,它们既会用在读请求中,也会用在写请求中。
Buffer 和 Cache 的设计目的,是为了提升系统的 I/O 性能。它们利用内存,充当起慢速磁盘与快速 CPU 之间的桥梁,可以加速 I/O 的访问速度。
4.cachestat 和 cachetop
安装:
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD
echo "deb https://repo.iovisor.org/apt/xenial xenial main" | sudo tee /etc/apt/sources.list.d/iovisor.list
sudo apt-get update
sudo apt-get install -y bcc-tools libbcc-examples linux-headers-$(uname -r)
export PATH=$PATH:/usr/share/bcc/tools
cachestat 提供了整个系统缓存的读写命中情况。
HITS MISSES DIRTIES HITRATIO BUFFERS_MB CACHED_MB0 0 0 0.00% 25 7588 0 2 100.00% 25 7582 0 1 100.00% 25 758
指标解释如下:
TOTAL ,表示总的 I/O 次数;
MISSES ,表示缓存未命中的次数;
HITS ,表示缓存命中的次数;
DIRTIES, 表示新增到缓存中的脏页数;
BUFFERS_MB 表示 Buffers 的大小,以 MB 为单位;
CACHED_MB 表示 Cache 的大小,以 MB 为单位。
cachetop 提供了每个进程的缓存命中情况。
$ cachetop
11:58:50 Buffers MB: 258 / Cached MB: 347 / Sort: HITS / Order: ascending
PID UID CMD HITS MISSES DIRTIES READ_HIT% WRITE_HIT%13029 root python 1 0 0 100.0% 0.0%
它的输出跟 top 类似,默认按照缓存的命中次数(HITS)排序,展示了每个进程的缓存命中情况。具体到每一个指标,这里的 HITS、MISSES 和 DIRTIES ,跟 cachestat 里的含义一样,分别代表间隔时间内的缓存命中次数、未命中次数以及新增到缓存中的脏页数。
而 READ_HIT 和 WRITE_HIT ,分别表示读和写的缓存命中率。
5.memleak
专门用来检测内存泄漏的工具memleak,memleak 可以跟踪系统或指定进程的内存分配、释放请求,然后定期输出一个未释放内存和相应调用栈的汇总情况(默认 5 秒)。
# -a 表示显示每个内存分配请求的大小以及地址
# -p 指定案例应用的PID号
# pidof 命令用于查找指定进程名称对应的进程 ID(PID)(pidof nginx)
root@node02:~# /usr/share/bcc/tools/memleak -a -p $(pidof app)
Attaching to pid 94810, Ctrl+C to quit.
cannot attach uprobe, Device or resource busy
[14:45:48] Top 10 stacks with outstanding allocations:addr = 7fbebc284340 size = 8192addr = 7fbebc286350 size = 8192addr = 7fbebc282330 size = 8192addr = 7fbebc280320 size = 8192addr = 7fbebc27e310 size = 819240960 bytes in 5 allocations from stackfibonacci+0x1f [app]child+0x4f [app]start_thread+0xdb [libpthread-2.27.so]
kswapd0专门的内核线程用来定期回收内存,为了衡量内存的使用情况,kswapd0 定义了三个内存阈值(watermark,也称为水位),分别是:
页最小阈值(pages_min)、页低阈值(pages_low)和页高阈值(pages_high)。剩余内存,则使用 pages_free 表示。
图表示它们的关系:
kswapd0 定期扫描内存的使用情况,并根据剩余内存落在这三个阈值的空间位置,进行内存的回收操作。
剩余内存小于页最小阈值,说明进程可用内存都耗尽了,只有内核才可以分配内存。
剩余内存落在页最小阈值和页低阈值中间,说明内存压力比较大,剩余内存不多了。这时 kswapd0 会执行内存回收,直到剩余内存大于高阈值为止。 剩余内存落在页低阈值和页高阈值中间,说明内存有一定压力,但还可以满足新内存请求。
剩余内存大于页高阈值,说明剩余内存比较多,没有内存压力。
我们可以看到,一旦剩余内存小于页低阈值,就会触发内存的回收。这个页低阈值,其实可以通过内核选项 /proc/sys/vm/min_free_kbytes 来间接设置。min_free_kbytes 设置了页最小阈值,而其他两个阈值,都是根据页最小阈值计算生成的,计算方法如下 :
pages_low = pages_min*5/4
pages_high = pages_min*3/2
6.numactl
查看处理器在 Node 的分布情况,以及每个 Node 的内存使用情况。比如,下面就是一个 numactl 输出的示例:
这个界面显示,我的系统中只有一个 Node,也就是 Node 0 ,而且编号为 0 和 1 的两个 CPU, 都位于 Node 0 上。另外,Node 0 的内存大小为 3919MB,剩余内存为 1055 MB。
7.sar
# 间隔1秒输出一组数据
# -r表示显示内存使用情况,-S表示显示Swap使用情况
root@node02:~# sar -r -S 1
Linux 4.15.0-213-generic (node02) 01/30/2024 _x86_64_ (2 CPU)03:39:42 PM kbmemfree kbavail kbmemused %memused kbbuffers kbcached kbcommit %commit kbactive kbinact kbdirty
03:39:43 PM 1029744 2052872 2983496 74.34 70060 1048668 2222692 17.92 917792 430188 59203:39:42 PM kbswpfree kbswpused %swpused kbswpcad %swpcad
03:39:43 PM 8388604 0 0.00 0 0.00
内存使用情况指标解释如下:
kbmemfree:可用内存,以 KB 为单位。
kbavail:可用于用户进程的内存,包括缓冲区和缓存,以 KB 为单位。
kbmemused:已使用的内存,以 KB 为单位。
%memused:已使用内存的百分比。
kbbuffers:用于缓冲的内存,以 KB 为单位。
kbcached:用于缓存的内存,以 KB 为单位。
kbcommit,表示当前系统负载需要的内存。它实际上是为了保证系统内存不溢出,对需要内存的估计值。%commit,就是这个值相对总内存的百分比。
kbactive,表示活跃内存,也就是最近使用过的内存,一般不会被系统回收。
kbinact,表示非活跃内存,也就是不常访问的内存,有可能会被系统回收。
kbdirty:脏页内存,以 KB 为单位。
交换空间使用情况指标解释如下:
kbswpfree:可用的交换空间,以 KB 为单位。
kbswpused:已使用的交换空间,以 KB 为单位。
%swpused:已使用交换空间的百分比。
kbswpcad:缓存的交换空间,以 KB 为单位。
%swpcad:缓存的交换空间的百分比。
常见的优化思路有这么几种。
最好禁止 Swap。如果必须开启 Swap,降低 swappiness 的值,减少内存回收时 Swap 的使用倾向。
减少内存的动态分配。比如,可以使用内存池、大页(HugePage)等。 尽量使用缓存和缓冲区来访问数据。比如,可以使用堆栈明确声明内存空间,来存储需要缓存的数据;或者用 Redis 这类的外部缓存组件,优化数据的访问。
使用 cgroups 等方式限制进程的内存使用情况。这样,可以确保系统内存不会被异常进程耗尽。
通过 /proc/pid/oom_adj ,调整核心应用的 oom_score。这样,可以保证即使内存紧张,核心应用也不会被 OOM 杀死。
帮助文献:极客时间的Linux性能优化实战