📌 说明(请先看这一句)
这份笔记的原文内容出自 小林coding 的《Linux 命令面试题》 ,我这份是把原文和我自己在 DeepSeek Harness 里逐条追问、补充理解后搭配整理出来的学习笔记。
原本的笔记是小林coding 的,我们这是搭配来看的,我不是原作者。 原文版权归小林coding 所有,建议对着原文一起看:https://xiaolincoding.com/interview/linux.html
笔记里的标记约定:
标记 含义 ⭐ 重点·内存 内存相关的重点,面试高频,也是本篇着重标注的部分 🔤 命名溯源 这条命令/参数是由哪几个英文单词拼出来的 💡 补充理解 我在原文之外自己追问补充的内容 ⚠️ 易错点 容易记混、写错的地方
Linux 命令面试题 · 学习笔记
⭐ 本篇重点(内存部分,优先看)
如果你时间不多,只想看内存,直接跳到第八节,按这个顺序看:
- top 和 free 都能看内存,区别在哪 → 8.1
- 怎么判断服务器内存够不够用 / 性能瓶颈是不是内存 → 8.2
- 如何判断内存是不是满了,用什么指标看使用率 → 8.3
- ⭐ 怎么判断操作系统有没有在内存替换、怎么统计内存替换的频率 → 8.4(压轴,含
pgscank/spgscand/spgsteal/s的完整拆解) - 「内存替换」到底是不是 Swap → 8.5
一、Linux 的常用命令了解过哪些?
按用途分类背,比背清单好记:
| 分类 | 命令 |
|---|---|
| 文件相关 | mv mkdir cd ls |
| 进程相关 | ps top kill pkill |
| 权限相关 | chmod chown useradd groupadd |
| 网络相关 | netstat ip addr |
| 测试相关 | 测试网络连通性 ping,测试端口连通性 telnet |
🔤 命名溯源
| 命令 | 全称 | 拆解 |
|---|---|---|
ls |
l ist | 列表 |
cd |
c hange directory | 改变目录 |
mv |
m ove | 移动(也用于重命名) |
mkdir |
m ak e directory | 创建目录 |
chmod |
ch ange mode | 改变模式(权限位) |
chown |
ch ange owner | 改变属主 |
ps |
p rocess status | 进程状态 |
kill |
kill | 发送信号,不一定真「杀掉」 |
二、ps 命令里都有哪些选项,ps 展示哪些东西?
ps 展示的内容
| 字段 | 含义 |
|---|---|
PID |
进程 ID |
PPID |
父进程 ID |
USER |
进程所属用户 |
%CPU |
CPU 占用率 |
%MEM |
内存占用率 |
VSZ |
虚拟内存大小 |
RSS |
物理内存大小(常驻内存) |
TTY |
终端设备 |
STAT |
进程状态 |
START |
进程启动时间 |
TIME |
进程累计 CPU 占用时间 |
COMMAND |
进程命令或可执行文件 |
💡
VSZ= V irtual memory S iZ e,RSS= R esident S et S ize(常驻集大小,真正占着物理内存的那部分)。面试常问:VSZ 很大不代表真的占了很多物理内存,因为虚拟内存是「许诺」出去的地址空间,物理内存页是惰性分配的。
ps 的常用选项
| 选项 | 英文来源 | 含义 |
|---|---|---|
-a |
all | 显示与终端关联的所有进程(含其他用户的,但不含会话首进程)。注意它并不等同于 -e |
-u |
user | 显示用户相关的进程信息 |
-x |
无终端 | 显示没有控制终端的进程 |
-e |
every process | 显示系统中所有进程,等同于 -A |
-f |
full | 显示详细进程信息(含父进程、运行状态等) |
-l |
long | 长格式输出(PID、PPID、CPU 占用率等) |
-r |
running | 只显示正在运行的进程 |
-o |
output format | 自定义输出格式 |
⚠️ 易错点 :ps -a 和 ps -e 经常被当成一回事,其实不是。记法:-a 是「有终端的」,-e 是「全部」。
三、top 命令会展示什么,每一项都是什么数据?
| 区域 | 内容 |
|---|---|
| Load average(平均负载) | 系统在最近 1 分钟、5 分钟、15 分钟的平均负载 |
| Tasks(任务) | 当前运行、睡眠、停止、僵尸状态的进程数量 |
| CPU usage(CPU 使用情况) | 总体使用率 + 每个核心的使用率 |
| Memory usage(内存使用) | 物理内存的总量、已用、空闲、buffer、cache |
| Swap usage(交换空间) | 交换空间的总量、已用、剩余 |
| 进程列表 | PID、用户、CPU 占用率、内存占用率、状态、启动时间、命令 |
🔤 top 这个名字的常见解释是 table of processes(进程表格),更朴素的理解就是「把最活跃的进程排到最上面」,所以叫 top。
💡 在 top 里按数字 1,可以把 CPU 展开成每个核心一行 ------ 这就是「top 怎么查看有多少个 CPU 核心」的答案。
四、进程与线程:查看状态、杀进程
已知一个进程名,如何杀掉这个进程?
方式一:ps + kill 两步走
bash
ps -ef | grep <进程名> # 先找到 PID
kill <PID> # 发 SIGTERM(15),优雅终止
kill -9 <PID> # 发 SIGKILL(9),强制终止
方式二:直接按进程名杀(推荐)
bash
pkill <进程名> # 按进程名模糊匹配并杀死
pkill -9 <进程名> # 强制终止
killall <进程名> # 按进程名精确匹配,杀死所有同名进程
💡 原则:优先 SIGTERM(kill <PID>),让进程做完清理再退出;只有在进程不响应、卡死时才用 SIGKILL(kill -9) ,因为 -9 不给进程任何收尾机会,可能造成文件/锁/中间状态损坏。
🔤 命名溯源 :pkill = p attern kill (按模式匹配杀);killall = kill all(同名全杀)。
如何查看进程状态?
用 ps 或 top。top 除了能看进程状态,还能看到系统信息(负载、内存、CPU 使用率)。
如何查看线程状态?
在 ps 和 top 上加参数:
bash
top -H
ps -eT | grep <进程名或线程名>
🔤 命名溯源(容易被问的参数)
| 写法 | 英文来源 | 说明 |
|---|---|---|
top -H |
tHreads | 大写 -H 表示 Threads mode(线程模式),显示每个独立线程。它不是严格的「首字母」缩写------因为 T 已被别的用途占用了,所以取了 H |
top -h |
help | 小写 -h 通常是显示帮助信息,别写混 |
ps -e |
every process | 显示所有进程 |
ps -T |
Threads | 显示每个进程的线程 |
⚠️ top -H 里的大写 -H 是本节最容易记错的点:大小写敏感,-H 看线程、-h 看帮助。
五、网络相关:连接、端口、连通性
如何查看网络连接情况?
bash
netstat -napt
输出的是服务器上的 TCP 连接状态,可以看到每个 TCP 连接的状态,以及四元组信息(源 IP、目标 IP、源端口、目标端口)。
🔤 -napt 是四个短参数合并书写 ,等价于 -n -a -p -t:
| 参数 | 英文 | 含义 |
|---|---|---|
-n |
numeric | 用数字显示 IP 和端口,不做主机名/服务名解析 |
-a |
all | 显示所有套接字(监听 + 已建立连接) |
-p |
p rocess / program | 显示占用套接字的进程信息 |
-t |
TCP | 只显示 TCP 套接字 |
参数顺序可以调整,所以下面几种写法一般等价:
bash
ss -napt
ss -ntap
ss -t -n -a -p
💡 现在更推荐 ss(socket statistics,套接字统计),它是较新的工具,通常比逐渐被淘汰的 netstat 更快。查看其他用户的进程信息可能需要 sudo。
怎么查看哪个端口被哪个进程占用?
用 lsof:
bash
lsof -i :80
text
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 929 root 6u IPv4 15249 0t0 TCP *:http (LISTEN)
nginx 934 nginx 6u IPv4 15249 0t0 TCP *:http (LISTEN)
用 netstat:
bash
netstat -napt | grep ':80 '
text
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 929/nginx: master p
⚠️ 易错点:grep 80 会匹配所有含 "80" 的字符 (比如 8080、甚至 PID 里含 80 的行),过滤不准确。推荐用 grep ':80 '(冒号 + 空格)来精确定位端口字段,或者直接用:
bash
ss -lntp sport = :80
🔤 命名溯源
| 命令 / 参数 | 全称 | 拆解 |
|---|---|---|
lsof |
L ist O pen Files | 列出已打开的文件。Linux「一切皆文件」,所以网络连接、端口监听也算「文件」,lsof 才能查端口 |
-i |
internet address | 选择网络文件 |
-n |
no hostname lookup | 不把 IP 反解析成主机名 |
-P |
P no port-name conversion | 不把端口号转换成服务名(注意是大写 -P) |
-sTCP:LISTEN |
state | 只看 TCP 的 LISTEN 状态 |
netstat |
net work statistics | 网络统计 |
ss |
s ocket statistics | 套接字统计 |
最常用的组合:
bash
sudo lsof -nP -iTCP -sTCP:LISTEN # 谁监听了哪些 TCP 端口
sudo lsof -nP -i :8080 # 谁占用了 8080
端口通不通用什么命令?
方式一:telnet
bash
telnet IP地址 端口号
能建立连接 = 端口通畅;连接失败或超时 = 端口不可访问。
方式二:nc(netcat)
bash
nc -zv IP地址 端口号
💡 更现代的替代写法:
bash
nc -vz 10.0.0.5 8080
curl -v http://10.0.0.5:8080
🔤 命名溯源(telnet 是常被问的)
text
telnet = TELetype + NETwork
(也常写作 TELecommunication NETwork,但更准确的历史来源是 TELeTYPE NETwork)
⚠️ Telnet 用户名、密码、数据都是明文传输 ,不适合远程登录,远程登录请用 ssh user@host;telnet 现在主要用于临时测试 TCP 端口连通性。
六、权限:修改文件权限用什么命令?
用 chmod。
bash
chmod 400 file.txt # 只读
chmod 644 file.txt # 属主读写,其他用户只读
chmod 755 file.txt # 属主读写执行,所属组读执行,其他用户只读
chmod 755 directory/ # 目录同理
权限位从左到右依次是:
text
u g o
属主 所属组 其他用户
数值由权限相加得出:
| 数值 | 权限 | 英文 |
|---|---|---|
| 4 | 读 | read |
| 2 | 写 | write |
| 1 | 执行 | execute |
所以 7 = 4+2+1 = rwx,5 = 4+1 = r-x,4 = r--。
⚠️ 易错点:第三组不是「其他组员」,而是「其他所有用户」 (既不是文件属主、也没通过所属组匹配到的用户)。第一组也应说成文件属主,不一定等于当前执行命令的用户。
💡 ls -l 输出的最前面那个字符不是权限位 ,而是文件类型:- 普通文件、d 目录、l 符号链接。
text
-rwxr-xr-- 1 alice developers 1234 file
│└┬┘└┬┘└┬┘
│ u g o
└ 文件类型
🔤 chmod = ch ange mode(改变模式)。
七、文本处理:sed / awk / grep 与日志统计
用 shell 命令替换一个文件中的字符串
bash
sed -i 's/旧字符串/新字符串/g' 文件名
sed -i 's/Hello/Hi/g' example.txt
| 部分 | 英文来源 | 含义 |
|---|---|---|
sed |
s tream editor | 流编辑器 |
-i |
in-place | 直接修改原文件(不输出到标准输出) |
s |
substitute | 替换 |
g |
global | 全局替换,一行中所有匹配项都换 |
💡 建议先备份:
bash
sed -i.bak 's/Hello/Hi/g' example.txt # 会生成 example.txt.bak
⚠️ sed -i 需要修改文件,因此对文件(通常还有所在目录,因为它可能创建临时文件再替换)必须有写权限。不要动不动就 chmod 777。
sed 和 awk 有什么区别?
sed:主要用于对文本进行替换、删除、插入 ,适合对整行文本处理,支持正则匹配。awk:能实现更复杂的文本处理逻辑,包括按字段操作、条件判断、循环 ,适合处理结构化文本(按列处理)。
一句话:sed 适合简单的替换编辑,awk 适合结构化数据的复杂处理。
🔤 命名溯源(awk 是最有名的「不是缩写」)
text
awk 不是功能缩写,而是三位创始人姓氏的首字母:
A --- Alfred Aho
W --- Peter Weinberger
K --- Brian Kernighan
awk 常见用法:
bash
awk '{print $1}' file.txt # 打印第 1 个字段
awk -F: '{print $1}' /etc/passwd # -F = Field separator,指定分隔符为冒号
查找日志中某个字符串出现的次数 / 匹配行的长度?
这里其实是两类不同需求,一定要分清:
需求一:统计包含某个字符串的每一行的长度(不是字符串本身的长度)
bash
grep "search_string" log_file | awk '{ print length }'
grep "search_string" log_file:找出日志中包含search_string的所有行;awk '{ print length }':输出每一行的字符数(length默认等同于length($0))。
需求二:统计某个字符串在日志中出现的次数
bash
grep -o "search_string" log_file | wc -l # 方式1:每一次匹配都算
grep -c "search_string" log_file # 方式2:统计包含它的行数
🔤 相关命令/参数的字母来源:
| 写法 | 全称 | 含义 |
|---|---|---|
grep |
g /re /p | 来自编辑器命令 g/re/p:g lobal / re gular expression / print |
grep -o |
only-matching | 只输出匹配到的片段,不输出整行 |
grep -c |
count | 统计匹配的行数 |
grep -i |
ignore case | 忽略大小写 |
grep -F |
Fixed strings | 按普通固定字符串搜索,不当正则 |
wc |
w ord count | 统计工具 |
wc -l |
lines | 行数 |
wc -c |
byte count | 字节数 |
wc -m |
characters | 字符数(UTF-8 下中文一个字算 1) |
echo -n |
no newline | 不追加换行符 |
⚠️ 易错点(原文也特意点出的一个误区)
bash
grep "c" log_file | wc -m
这条命令会先取出所有包含 c 的整行 ,再统计这些行的总字符数 (通常还包含每行的换行符),结果和「字符 c 出现了几次」完全不同,千万别用它来统计字符出现次数。
统计 c 出现了几次,应该用:
bash
grep -o "c" log_file | wc -l
举个具体例子,文件内容:
text
abc
cat
hello
success
| 命令 | 统计的是什么 | 结果 |
|---|---|---|
| `grep "c" log_file | wc -m` | 匹配行的总字符数 |
| `grep -o "c" log_file | wc -l` | 字符 c 的总出现次数 |
grep -c "c" log_file |
包含 c 的行数 |
3 |
一句话记忆:
grep -o | wc -l数「出现次数」,grep -c数「匹配行数」,| wc -m数「整行总字符数」------三个完全不同的东西。
💡 顺带一个高频疑问:grep 抓出来的东西会打印到屏幕吗? 会------默认输出到标准输出(stdout)。它虽然显示在屏幕上,但本质是标准输出,所以还能继续用管道传下去:
bash
grep "error" log_file # 直接显示匹配的整行
grep "error" log_file | wc -l # 交给 wc 统计,屏幕只显示数字
grep "error" log_file > result.txt # > 重定向写文件,屏幕不显示
grep "error" log_file | tee result.txt # tee:既显示又保存
日志里取耗时最高的 10 条
日志格式:第一列日期、第二列请求 IP、第三列请求耗时。
bash
sort -k3 -nr 日志文件 | head -n 10
| 部分 | 英文来源 | 含义 |
|---|---|---|
sort |
sort | 排序(默认按文本字典序,不是数值) |
-k3 |
key | 以第 3 个字段作为排序键 |
-n |
numeric sort | 按数值大小排序 |
-r |
reverse | 倒序(从大到小) |
-nr |
-n -r | 按数字从大到小 |
head |
head | 取开头若干行 |
-n 10 |
number of lines | 前 10 行 |
tail -n +2 |
--- | 从第 2 行开始输出(跳过表头) |
| ` | ` | pipe |
⚠️ 易错点:严格来说 -k3 表示排序键「从第 3 列开始一直到行末」,后面还有第 4、5 列也可能参与比较。只想按第 3 列排,推荐写:
bash
sort -k3,3 -n -r 日志文件 | head -n 10
sort -k3,3nr 日志文件 | head -n 10 # 等价简写
如果第一行是表头,别让它参与排序:
bash
tail -n +2 日志文件 | sort -k3,3nr | head -n 10
🔤 为什么管道里的中间结果不显示?因为 sort 的输出进管道了,屏幕最终只会显示 head 的那 10 行。
⚠️ 安全提示 :sudo rm -f * 这种命令会删掉当前目录所有非隐藏文件(* 不匹配 .env、.git 等以点开头的项),-f 还不询问确认。想先看看会匹配什么:
bash
printf '%q\n' ./* # 安全预览
ls -la
八、⭐ 内存专题(本篇重点)
这一节是全篇的重点。前面那些是「知道怎么写」,内存这块是「知道怎么判断」,面试和线上排障的分水岭都在这里。
8.1 ⭐ top 命令和 free 命令都可以查看内存,有什么区别?
free 专注看内存使用情况:
物理内存部分:
| 字段 | 含义 |
|---|---|
total |
总物理内存大小 |
used |
已使用的内存 |
free |
未使用的内存 |
shared |
共享内存大小 |
buff/cache |
缓冲和缓存内存大小 |
available |
⭐ 当前可用的内存,考虑到了部分缓存可以被快速释放的情况 |
交换内存部分:total、used、free。
top 除了显示内存,还会显示系统任务情况、CPU 使用情况、各进程状态等信息。
⭐ 核心区别一句话 :
free是「内存专用仪表盘」,top是「系统全景仪表盘」,内存只是 top 的一个区块。
💡 补充理解(内存里第一个大坑) :看内存不要只看free。Linux 会主动把空闲内存拿去做 page cache(文件缓存),所以free很小经常是正常的 ,甚至是「内存被高效利用」的表现。真正代表「还能拿来用多少」的是available。记法:
free小 ≠ 内存不够;available低才是真的紧张。 而buff/cache里的内容,大部分在需要时可以被内核立刻丢掉或写回,所以它被算进了available。
8.2 ⭐ 怎么判断服务器内存是否够用?如何查看服务器性能瓶颈是否是内存?
① 用 free 看总体情况
bash
free -m
text
total used free shared buff/cache available
Mem: 7982 1746 2523 155 3703 5818
Swap: 2047 6 2041
重点看:used(已用)、free(空闲)、available(真正可用,含可快速释放的缓存,最能代表实际可用内存)。
⭐
available的值长期很低,就可能表明内存不足。
② 观察是否频繁使用 Swap 空间
bash
Swap: 2047 6 2041
如果 Swap 使用过多(例如接近 Swap total),说明物理内存不足。
③ 检查 dmesg 是否有 OOM
bash
dmesg | grep -i "out of memory"
也可以看 /var/log/messages。存在 OOM 错误,说明内存不足是明显问题。
🔤 命名溯源:dmesg 通常理解为 d iagnostic mes sag es(诊断消息),也有解释为 display messages。它读取的是 Linux 内核环形缓冲区(kernel ring buffer)里的消息,内核启动、驱动加载、磁盘/文件系统错误、OOM 都在里面。
bash
dmesg -T # -T:human-readable timestamps,把 [12345.6789] 转成可读日期时间
dmesg -w # -w:follow/wait,持续等待并显示新消息
dmesg -l err,warn # -l:level,只看错误和警告等级
sudo dmesg # 现代 Linux 普通用户可能读不到内核日志
journalctl -k # systemd 环境下的替代,-k = kernel,只看内核日志
④ 用 vmstat 观测内存使用状况
bash
vmstat 1 # 每秒刷新一次
特别关注:
- ⭐
si(swap in)和so(swap out) :这两个值较高,说明系统频繁使用交换空间,表明物理内存可能不足; free:空闲内存;buff和cache:缓存和缓冲区使用情况。
🔤 vmstat = v irtual m emory statistics(虚拟内存统计)。
8.3 ⭐ 如何判断内存是否是满的情况?通过什么指标判断内存的使用率?
四条判据,逐条对照:
- ⭐
free和available都非常低,而used很高 → 内存基本上是满的; - ⭐ Swap 使用频繁且使用率较高 → 内存基本上是满的;
- ⭐
dmesg日志里出现 OOM 相关信息 → 内存不足已经导致进程被杀掉; - ⭐
ps或top显示大部分内存被少数几个进程占用 → 内存基本上是满的。
💡 补充理解 :这四条其实分别对应「当前状态」「换页行为」「历史事故」「责任方」四个维度------
available是当下快照,si/so是动态行为,OOM 是已经发生过的结果,ps/top用来定位是谁吃掉的。排障时按这个顺序走一遍,基本不会漏。
8.4 ⭐⭐ 怎么判断操作系统有没有在内存替换?或者说怎么统计内存替换的频率?(本篇压轴)
原文答案:用 sar -B 1 命令观察。
bash
sar -B 1 # 每 1 秒输出一组分页统计数据
sar -B 1 5 # 每 1 秒采样一次,共输出 5 次
# Ctrl+C 停止
🔤 命名溯源:sar 这个名字是怎么拼出来的
sar=SystemActivityReporter (系统活动报告器),也有写作 System Available Reporter 的说法。也就是取 System + Activity + Reporter 这几个英文单词的(首)字母拼成的 s-a-r ,全小写就是命令名
sar。它通常包含在
sysstat软件包中,用来持续采集并报告 CPU、内存、磁盘、网络等系统活动指标。它和mpstat、iostat、pidstat是同一个家族的工具,都是「stat / 统计类 」工具,采集的数据落在/var/log/sa/下,所以sar还能回看历史(不写时间就是看今天)。
再看 -B 和无参数的 1:
| 写法 | 含义 |
|---|---|
-B |
查看 Paging statistics(内存分页统计) 相关指标。这里的大写 B 是 sar 规定的选项字母,不建议硬记成某个英文单词的首字母,重点记住它用于显示分页及内存回收情况 |
1 |
每隔 1 秒输出一组统计数据 |
⭐ 重点看哪三个指标
text
pgscank/s pgscand/s pgsteal/s
原文图中红框标出的,就是后台内存回收 和直接内存回收的指标。
🧩 把这几个名字一个一个拆开
text
pg = page,内存页
scan = 扫描
k = kswapd,内核后台回收线程
d = direct,直接(回收)
steal = 回收、夺回
/s = per second,每秒
| 指标 | 拆解 | 原文定义 |
|---|---|---|
⭐ pgscank/s |
pg + scan + k(swapd) + /s | kswapd(后台回收线程)每秒扫描的 page 个数 |
⭐ pgscand/s |
pg + scan + d(irect) + /s | 应用程序在内存申请过程中 每秒直接扫描的 page 个数 |
⭐ pgsteal/s |
pg + steal + /s | 扫描的 page 中每秒被回收的个数 |
⭐⭐ 记忆点(建议背下来)
这几个指标名字里都带
scan,不是巧合------因为内核要判断一个内存页到底能不能回收、或者要回收多少内存,唯一的手段就是去「扫描」内存页。区别只在于谁在扫、什么时候扫:
pgscank/s:内核的后台线程kswapd在扫,它提前、异步地扫,判断哪些页可以回收,扫完就顺手回收一部分;pgscand/s:应用程序自己「被逼着」现场扫(direct reclaim,直接内存回收),因为它申请内存时系统已经没有空闲内存了,只能同步扫描、腾出页面,扫完才能拿到内存;pgsteal/s:不是另一个「扫描动作」,而是扫描之后真正成功回收走的页数------即「扫描」和「回收」是两件事:扫了很多页,不代表都能 steal 成功。🔤 顺带记一下
kswapd= kernel swap daemon (内核交换守护进程),名字里的 swap 是历史沿用,它实际干的是页回收 + 必要时换出 ;swap这个词本身就是「交换」,daemon是「守护进程」。
⭐ 三个指标怎么解读
① pgscank/s 高:后台回收在干活
text
内存开始紧张
↓
内核唤醒 kswapd
↓
kswapd 在后台扫描内存页
↓
回收一部分内存
出现一定的 pgscank/s 不一定说明系统有严重问题,因为后台回收本身就是正常机制。如果该指标长期很高,说明系统持续面临内存压力。
② pgscand/s 高:⚠️ 这才是要警惕的
text
Java 程序申请内存
↓
系统没有足够的空闲内存
↓
申请不能立即完成
↓
程序自己进入直接回收流程
↓
扫描并释放可回收页面
↓
继续申请内存
由于应用程序必须等待回收完成,这段时间表现为:请求延迟突然增高、程序偶尔卡住、系统周期性抖动、接口响应时间出现尖刺。
⭐
pgscand/s持续较大,通常比pgscank/s较大更值得警惕。
③ pgsteal/s 高:确实回收掉了不少页
系统每秒成功回收了多少个内存页。
⚠️ 补充理解(原文这里有个容易误读的括号):原文写的是
text
pgsteal/s: 扫描的 page 中每秒被回收的个数(pgscank+pgscand)
这里的 (pgscank+pgscand) 不是让你做加法 ,即下面这个等式通常不成立:
text
pgsteal/s = pgscank/s + pgscand/s ❌
它只是想说「这两个来源扫出来的页合起来,最终有多少被回收」。正确关系是:
text
pgscank/s = 后台扫描了多少页
pgscand/s = 直接回收扫描了多少页
pgsteal/s = 扫描后真正成功回收了多少页
举例:
text
pgscank/s = 1000
pgscand/s = 500
pgsteal/s = 600
意思是:后台扫了 1000 页、直接回收扫了 500 页,最终成功回收 600 页------不是回收了 1500 页。
📊 看到输出怎么判断
text
pgscank/s pgscand/s pgsteal/s
0.00 0.00 0.00
500.00 0.00 300.00
1200.00 800.00 700.00
| 情况 | 现象 | 结论 |
|---|---|---|
| ⭐ 情况一 | 三个值基本都是 0.00 |
这个采样期间基本没有发生内存回收,内存压力通常不明显 |
| ⭐ 情况二 | pgscank/s 较高,pgscand/s 为 0 |
后台线程正在回收内存,但应用暂时没被迫直接回收。存在一定内存压力,但不一定造成明显卡顿,要结合其他指标 |
| ⭐ 情况三 | pgscand/s 持续较高 |
⚠️ 应用申请内存时触发了直接回收 。若与系统卡顿、接口延迟发生在同一时间段,很可能存在:内存压力 → 直接回收 → 应用被阻塞 → 系统抖动 |
⚠️ 不能仅凭某一次非零就认定系统有严重问题,要观察它是否:
- 持续出现;
- 数值很高;
- 与延迟尖刺同时发生;
- 同时伴随
available很低或换页活动。
🍽️ 后台回收 vs 直接回收(餐厅打比方,很好记)
后台回收 kswapd |
直接回收 direct reclaim |
|
|---|---|---|
| 场景 | 餐厅发现空桌快不够了,服务员提前清理 | 客人已经到了却没有空桌,只能站着等服务员现场收拾 |
| 对应指标 | pgscank/s |
pgscand/s |
| 对应用的影响 | 相对间接 | 直接阻塞申请内存的程序,容易造成延迟和卡顿 |
⭐ 原文最后一句的大白话版本:
如果系统时不时发生抖动,并且在抖动的时间段里
sar -B观察到pgscand数值很大,那大概率是因为「直接内存回收」导致的。
🧾 建议一起观察的指标组合
| 目的 | 命令 | 重点看 |
|---|---|---|
| 当前可用内存 | free -h |
⭐ available(不要只看 free) |
| 内存回收活动 | ⭐ sar -B 1 |
⭐ pgscank/s pgscand/s pgsteal/s |
| 是否在频繁换页 | vmstat 1 |
⭐ si so |
| 是否发生过 OOM | `dmesg | grep -Ei 'oom |
没权限读内核日志时:
bash
sudo dmesg | grep -Ei 'oom|out of memory|killed process'
journalctl -k | grep -Ei 'oom|out of memory|killed process'
8.5 ⭐ 「内存替换」中的「替换」就是 Swap 吗?
💡 结论:不完全是。 更准确的叫法是 内存回收(memory reclaim) ,而 Swap 只是内存回收可能采取的一种手段。
原文说的「内存替换」容易让人误解,根据它讨论的 pgscank/s、pgscand/s、pgsteal/s,称为内存回收更加准确。
内存紧张时,Linux 主要有两种腾空间的方式:
text
内存回收
├── ① 回收文件缓存:不一定使用 Swap
└── ② 换出匿名内存:使用 Swap
① 回收文件缓存(不涉及 Swap)
程序读过的文件内容会被缓存在内存里,内存不足时这些缓存页可以直接丢弃,因为以后需要时还能从磁盘文件重新读回来:
text
文件缓存页 → 丢弃 → 腾出物理内存
② 换出匿名内存(这才涉及 Swap)
程序通过堆、栈使用的匿名内存没有对应的磁盘文件,不能直接丢掉,内核可能把暂时不用的匿名页写入 Swap:
text
物理内存中的匿名页
↓ swap out
Swap 空间
↓ swap in
重新读回物理内存
这就是通常说的内存交换(swapping)。
所以 sar -B 看到的不只是 Swap :它反映的是广义的内存扫描和回收,不能仅凭这些指标断定正在使用 Swap。
怎么确认是否真的在进行 Swap?
bash
vmstat 1 # 重点看 si / so
text
si so
0 0
0 0
128 512 ← 这一行表示当前确实发生了 Swap 换入和换出
| 字段 | 英文 | 含义 |
|---|---|---|
⭐ si |
s wap in | 每秒从 Swap 读回内存的数据量 |
⭐ so |
s wap out | 每秒从内存写入 Swap 的数据量 |
也可以:
bash
sar -W 1 # -W:显示交换活动
| 字段 | 英文 | 含义 |
|---|---|---|
pswpin/s |
p age sw ap in | 每秒换入的页数 |
pswpout/s |
p age sw ap out | 每秒换出的页数 |
⭐ 一句话记忆 :内存回收不一定使用 Swap;只有把匿名内存页写到交换空间,才叫 Swap。
⚠️ 另外注意:Swap 已使用 ≠ 正在频繁换页 。系统可能过去把一些长期不用的页面放进了 Swap,而现在并没有频繁读写。判断当前 压力时,
si、so的变化比单看 Swap 已用了多少更重要。
九、CPU 与平均负载
假如 CPU 跑到 100%,你的解决思路是什么?
- 先用
top定位到占用 CPU 高的进程 PID; - 用
top -H -p <进程ID>或ps -T -p <进程ID>找到该进程中占 CPU 高的线程 ID(TID); - 查看对应线程的调用栈,按进程类型选工具:
- Java 进程 :把线程 ID 转成十六进制,用
jstack <进程ID>搜索对应线程的堆栈(jstack仅适用于 JVM 进程); - C/C++ 或其他 native 进程 :用
perf top -p <进程ID>、gdb -p <进程ID>或strace -p <线程ID>观察热点函数和系统调用;
- Java 进程 :把线程 ID 转成十六进制,用
- 根据堆栈信息回项目定位代码,看是否发生死循环、热点计算或频繁系统调用。
Linux 服务器如何查看负载情况?通过什么指标查看?
用 top 或 uptime,看最后的系统平均负载(Load Average)。
Load Average 的三个数字,依次是过去 1 分钟、5 分钟、15 分钟的平均负载。 通过三者大小可以判断负载趋势:
| 例子 | 趋势 |
|---|---|
1.00, 5.00, 10.00(依次增大) |
过去 1 分钟负载 < 过去 15 分钟 → 负载在下降 |
10.00, 5.00, 1.00(依次降低) |
过去 1 分钟负载 > 过去 15 分钟 → 负载在上升 |
0.07, 0.04, 0.00(基本相同) |
负载平稳 |
⭐ 负载值一般不超过 CPU 核数的 1~1.5 倍;超过 1.5 倍就要重视,此时会严重影响系统。
平均负载 ≠ CPU 使用率:
- 平均负载是单位时间内处于可运行状态和不可中断状态的进程数 ------不仅包括正在用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程;
- CPU 使用率是单位时间内 CPU 繁忙情况的统计。所以:
| 场景 | 平均负载 | CPU 使用率 |
|---|---|---|
| CPU 密集型进程 | 升高 | 高(两者一致) |
| I/O 密集型进程 | 升高 | 不一定高 |
| 大量进程等待 CPU 调度 | 升高 | 也比较高 |
所以负载高了要先分清是 CPU 高还是 iowait 高:
bash
mpstat -P ALL 1
text
07:51:45 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle
07:51:50 PM all 42.90 0.00 49.39 0.41 0.00 4.56 0.00 0.00 2.74
07:51:50 PM 0 44.38 0.00 48.67 0.41 0.00 2.86 0.00 0.00 3.68
07:51:50 PM 1 41.57 0.00 49.80 0.40 0.00 6.43 0.00 0.00 1.81
从上面可以看出 %usr 约 45%、%sys 约 50%、%iowait 只有 0.41%、%idle 只剩 2~3% ------ 可以推断是 CPU 使用率导致平均负载升高。
反过来说,如果只有 %iowait 高 ,%usr、%sys 都很轻松,那负载升高就是 iowait 导致的。
再定位是哪个进程导致的:
bash
pidstat -u 1
text
08:07:55 PM PID %usr %system %guest %CPU CPU Command
08:07:56 PM 11 0.00 16.00 0.00 16.00 0 events/0
08:07:56 PM 12 0.00 20.00 0.00 20.00 1 events/1
可以看到是 events/0、events/1 这两个内核进程 CPU 使用率非常高,可能是它们导致平均负载升高。
🔤 命名溯源
| 命令 | 全称 | 拆解 |
|---|---|---|
mpstat |
M ultip rocessor Statistics | 多处理器统计 |
pidstat |
P rocess ID Statistics | 按进程 ID 统计 |
iostat |
I nput/O utput Statistics | I/O 统计 |
vmstat |
V irtual M emory Statistics | 虚拟内存统计 |
sar |
S ystem A ctivity Reporter | 系统活动报告器 |
uptime |
up time | 系统已运行时长(顺带给出负载) |
mpstat 常见参数:
bash
mpstat -P ALL 1 # -P:processor,指定处理器;ALL:所有 CPU;1:每 1 秒输出一次
mpstat -P 0 1 # 只看 0 号 CPU
它来自 sysstat 包,没有的话:sudo apt install sysstat(Debian/Ubuntu)或 sudo yum install sysstat(CentOS/RHEL)。
mpstat 输出字段:
| 字段 | 英文 | 含义 |
|---|---|---|
%usr |
user | 用户态 CPU 使用率 |
%nice |
nice | 调整过优先级的用户进程占用率 |
%sys |
system | 内核态 CPU 使用率 |
%iowait |
I/O wait | 等待 I/O 的时间比例 |
%irq |
interrupt request | 硬中断占用率 |
%soft |
software interrupt | 软中断占用率 |
%steal |
steal time | 虚拟机被宿主机占用的时间 |
%idle |
idle | CPU 空闲率 |
十、命令命名溯源总表(首字母 / 缩写来源)
面试里「这个命令/参数是由哪些英文单词组成的」几乎必问,集中放一张表,考前扫一眼。
命令名
| 命令 | 来源 | 拆解 |
|---|---|---|
ls |
list | 列表 |
cd |
change directory | 改变目录 |
mv |
move | 移动/重命名 |
mkdir |
make directory | 创建目录 |
chmod |
change mode | 改变权限模式 |
chown |
change owner | 改变属主 |
ps |
process status | 进程状态 |
top |
table of processes | 进程表格(把最活跃的排最上面) |
free |
free memory | 空闲内存 |
kill / pkill / killall |
pattern kill / kill all | 按模式杀 / 全部杀 |
netstat |
network statistics | 网络统计 |
ss |
socket statistics | 套接字统计 |
lsof |
list open files | 列出已打开的文件 |
telnet |
TELetype + NETwork | 远程终端协议 |
nc |
netcat | 网络工具 |
sed |
stream editor | 流编辑器 |
awk |
Aho + Weinberger + Kernighan | 三位创始人姓氏首字母 |
grep |
g/re/p | global / regular expression / print |
sort / head / tail |
本义 | 排序 / 取头 / 取尾 |
wc |
word count | 统计行、字、字节 |
sar |
System Activity Reporter | 系统活动报告器(也有 System Available Reporter 的说法) |
mpstat |
multiprocessor statistics | 多处理器统计 |
pidstat |
process id statistics | 按进程统计 |
vmstat |
virtual memory statistics | 虚拟内存统计 |
iostat |
input/output statistics | I/O 统计 |
dmesg |
diagnostic messages | 诊断消息(内核环形缓冲区) |
journalctl |
journal control | systemd 日志查询 |
jstack |
JVM stack | JVM 线程堆栈(仅 JVM) |
strace |
system call trace | 系统调用跟踪 |
perf |
performance | 性能分析 |
kswapd |
kernel swap daemon | 内核交换守护进程(实际做页回收/换出) |
参数
| 参数 | 来源 | 含义 |
|---|---|---|
ps -a |
all | 有终端的全部进程 |
ps -e |
every | 所有进程 |
ps -u |
user | 用户相关 |
ps -f |
full | 完整信息 |
ps -l |
long | 长格式 |
ps -o |
output | 自定义输出 |
ps -T |
threads | 显示线程 |
top -H |
tHreads | 线程模式(大写 H,非严格首字母) |
top -h |
help | 帮助 |
netstat -n |
numeric | 不解析主机名/服务名 |
netstat -a |
all | 所有套接字 |
netstat -p |
process/program | 显示进程 |
netstat -t |
TCP | 只看 TCP |
lsof -n |
no hostname lookup | 不做反向解析 |
lsof -P |
no port-name conversion | 不做端口到服务名转换 |
lsof -i |
internet address | 网络文件 |
lsof -s |
state | 状态过滤 |
chmod 数字 |
r=4 / w=2 / x=1 | 相加组合 |
sed -i |
in-place | 原地修改 |
sed 的 s / g |
substitute / global | 替换 / 全局 |
awk -F |
Field separator | 字段分隔符 |
grep -o |
only-matching | 只输出匹配片段 |
grep -c |
count | 匹配行数 |
grep -i |
ignore case | 忽略大小写 |
grep -F |
fixed strings | 固定字符串 |
wc -l / -c / -m / -w |
lines / byte count / characters / words | 行 / 字节 / 字符 / 词 |
echo -n |
no newline | 不追加换行 |
sort -k |
key | 排序键 |
sort -n |
numeric | 数值排序 |
sort -r |
reverse | 倒序 |
head -n |
number of lines | 行数 |
nsenter 类 -n |
numeric | (同 netstat) |
sar -B |
Paging statistics | 分页统计(大写 B 是规定选项字母,不硬套单词) |
sar -W |
sWap | 交换活动 |
vmstat 的 si/so |
swap in / swap out | 换入 / 换出 |
sar -W 的 pswpin/s pswpout/s |
page swap in/out per second | 每秒换入/换出页数 |
mpstat -P |
processor | 处理器 |
pidstat -u |
CPU 指标 | CPU |
dmesg -T |
human-readable timestamps | 可读时间戳 |
dmesg -w |
follow/wait | 持续输出 |
dmesg -l |
level | 日志等级 |
journalctl -k |
kernel | 只显示内核日志 |
十一、⚠️ 全篇易错点速查(考前扫这一块)
| # | 易错点 | 正解 |
|---|---|---|
| 1 | top -H 写成 top -h |
大写 -H 看线程;小写 -h 是帮助 |
| 2 | 以为 ps -a 等于 ps -e |
-a 是「与终端关联的」进程,-e 才是「全部」 |
| 3 | grep 80 找端口 |
会误匹配 8080、PID 里的 80 → 用 grep ':80 ' 或 ss -lntp sport = :80 |
| 4 | `grep "c" file | wc -m` 当字符出现次数 |
| 5 | grep -c 当出现总次数 |
它数的是包含该串的行数,一行多次只算 1 |
| 6 | sort -k3 只按第 3 列 |
-k3 是「第 3 列到行末」;只排第 3 列用 -k3,3 |
| 7 | sort 直接按数值排 |
默认是字典序,数值要加 -n |
| 8 | 看 free 判断内存够不够 |
该看 available ;free 小常常是正常的缓存占用 |
| 9 | 「内存替换」= Swap | 内存回收包含回收文件缓存(不涉及 Swap);只有匿名页写到交换空间才叫 Swap |
| 10 | ⭐ pgsteal/s = pgscank/s + pgscand/s |
❌ 不成立。前两个是扫描量 ,pgsteal 是扫描后成功回收量 |
| 11 | Swap 已用高就当内存不足 | 要看 si/so 的变化,历史换出过不代表现在在频繁换页 |
| 12 | 只看负载数值判断瓶颈 | 负载含等待 I/O 的进程;要配合 mpstat 看 %iowait vs %usr/%sys |
| 13 | kill -9 当首选 |
先 SIGTERM(15) 优雅退出,卡死才 -9 |
| 14 | chmod 777 解决权限问题 |
权限开太大,按最小必要给 |
十二、一句话记忆卡(内存部分)
text
free 小 → 不一定内存不足(缓存占着);看 available
available 长期很低 → 内存不足
si / so 持续较高 → 正在频繁 Swap 换入换出,物理内存可能不足
dmesg 出现 OOM → 内存不足已经杀过进程了
pgscank/s 高 → 内核后台线程 kswapd 在提前扫页回收
有内存压力,但不一定直接卡住应用
pgscand/s 高 → 应用申请内存时被迫现场扫页回收(direct reclaim)
⚠️ 直接阻塞应用,容易造成卡顿和延迟抖动
pgsteal/s 高 → 系统确实回收掉了较多内存页
(≠ pgscank + pgscand,别做加法)
这三个指标都带 scan,因为内核判断页能不能回收、
要回收多少内存,唯一的办法就是去扫描内存页。
sar = System Activity Reporter(系统活动报告器)
System + Activity + Reporter → s-a-r
sar -B 1 → 看分页/内存回收(pgscank/s、pgscand/s、pgsteal/s)
sar -W 1 → 看交换活动(pswpin/s、pswpout/s)
记住这句总结:后台回收是在应用「还没要内存」时提前腾内存;直接回收是在应用「急着要内存」时现场腾内存。后者会直接阻塞应用,所以更容易造成系统抖动。
所以这个知识点真正要理解的不是背指标名,而是:看到
pgscand/s高,就要怀疑内存压力正在直接拖慢你的应用。
再次说明:原文出自 小林coding《Linux 命令面试题》 (https://xiaolincoding.com/interview/linux.html),我不是原作者,本笔记是搭配原文一起看的学习整理版,文中「💡 补充理解」部分是我自己的追问与展开。原文抓取时间:2026-09-20。