大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
进程管理
这一课你将能做到
- 用 ps、top/htop 查看系统进程状态,快速定位 CPU 或内存占用最高的进程
- 读懂
top输出的负载均值、进程状态缩写(R/S/D/Z/T),判断服务器是 CPU 瓶颈还是 I/O 瓶颈 - 正确使用 kill 信号(TERM/KILL/HUP)管理进程,知道什么情况下才允许
kill -9
为什么要学
服务器变慢了、接口超时了、Spring Boot 应用 CPU 飙到 100%——这类线上告警的第一响应就是进程排查。本站后端跑在 Linux 上,当监控显示负载异常时,你需要在三分钟内回答:哪个进程在吃资源?它是正常业务高峰还是死循环?能不能安全重启?
面试中,「load average 三个数字什么意思」「僵尸进程怎么产生怎么清理」「kill 和 kill -9 的区别」是出现频率最高的进程类问题。答得好说明你真有排障经验。
先建立图像
进程的生命周期状态(top 的 S 列):
fork() 运行 退出
│ │ │
▼ ▼ ▼
┌─────┐ ┌───────┐ ┌────────┐
│ R │←──→│ S │ │ Z │ ← 僵尸:已死但父进程没收尸
│运行 │ │ 睡眠 │ │ 僵尸 │
└──┬──┘ └───┬───┘ └────────┘
│ │
│ ┌────┴────┐
└─────→│ D │ T │ ← D:不可中断睡眠(等磁盘 I/O,危险信号)
│磁盘 │停 │ T:被暂停(Ctrl+Z 或 SIGSTOP)
└─────────┘
load average(负载均值):
0.50 1.20 2.00
│ │ └─ 15 分钟平均
│ └─────── 5 分钟平均
└────────────── 1 分钟平均
解读:数值 ÷ CPU 核数 ≈ 繁忙程度。4 核机器 load 4.0 = 满载,8.0 = 过载一倍
跟着做
步骤 1:ps——进程快照
# 经典组合:查看所有进程(BSD 风格,最常用)
ps aux | head -20
# 输出列解读:
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
# ↑ ↑ ↑ ↑ ↑
# 进程号 CPU 内存 实际物理内存 状态(R/S/D/Z/T)
# 查找特定进程(本站实战:找 Spring Boot 进程)
ps aux | grep java
ps aux | grep [j]ava # 加方括号排除 grep 自身,技巧
# 树状显示进程父子关系
pstree -p | head -30
# 按 CPU / 内存排序找大户
ps aux --sort=-%cpu | head -10 # CPU 占用前 10
ps aux --sort=-%mem | head -10 # 内存占用前 10
# 只看某个用户的进程
ps -u mysql
步骤 2:top——实时监控面板
top
进入后关键操作:
界面头部解读:
load average: 1.25, 0.80, 0.45 ← 负载趋势:1分 > 5分 > 15分 说明负载在上升
%Cpu(s): 12.5 us, 3.1 sy, 0.0 ni, 84.0 id, 0.2 wa
↑用户态 ↑内核态 ↑空闲 ↑I/O 等待(wa 高 = 磁盘瓶颈)
交互按键:
P 按 CPU 排序(默认)
M 按内存排序
k 输入 PID 杀进程(默认发 TERM)
1 展开显示每个 CPU 核
c 显示完整命令行(Java 进程全是 java,按 c 才能看到 jar 名)
q 退出
更友好的替代品(推荐安装):
sudo apt install -y htop
htop # 彩色界面、鼠标可操作、树状视图,功能同 top 但体验好得多
步骤 3:负载解读实战
uptime
# 输出:10:30:01 up 30 days, load average: 0.52, 0.58, 0.59
nproc # 查看 CPU 核数,比如 4
# 判断:load 0.52 / 4 核 = 13% 繁忙,非常健康
# 如果 4 核机器 load 是 6.0,说明排队严重,需要排查
负载高的两种典型场景:
# 场景 A:CPU 型负载(us 高)
top # %Cpu 的 us 接近 100%,且某个 java 进程 %CPU 300%
# 结论:应用计算密集或死循环,用 jstack 进一步分析 Java 线程
# 场景 B:I/O 型负载(wa 高)
top # wa 超过 20%,D 状态进程多
iostat -x 2 # 需安装 sysstat,确认磁盘 util% 接近 100%
# 结论:磁盘扛不住了,可能是 MySQL 慢查询刷盘或日志狂写
步骤 4:kill 与信号——优雅地杀死进程
# 信号不是「杀死」,是「发消息」,进程决定怎么响应
kill -l # 列出全部 64 个信号
# 三个必须记住的信号:
kill -15 1234 # SIGTERM(默认):请优雅退出(关连接、存数据)
kill -9 1234 # SIGKILL:立即枪决,进程无法拦截
kill -1 1234 # SIGHUP:传统上让进程重读配置(Nginx reload 的底层)
# 按名字杀
pkill -f "codeforge.jar" # 按完整命令行匹配(-f 很重要,否则匹配不到)
killall java # 按进程名杀(所有 java 进程,慎用)
正确的杀进程顺序(生产纪律):
kill 1234 # 1. 先发 TERM,等它优雅退出
sleep 10
ps -p 1234 # 2. 检查是否还在
kill -9 1234 # 3. 实在不退才上 KILL
为什么 kill -9 是最后手段:进程没有机会执行清理逻辑——Spring Boot 的停机钩子、数据库连接关闭、缓冲区刷盘全部跳过,可能导致数据不一致或连接泄漏。MySQL 被 kill -9 后下次启动要崩溃恢复。
步骤 5:前台、后台与终端断开
# 前台运行,终端被占住
java -jar app.jar
# Ctrl+Z 暂停,进程进入 T 状态
# bg 让它在后台继续跑
bg
# jobs 查看当前终端的后台任务
jobs
# fg %1 拉回前台
fg %1
# 启动时就放后台
java -jar app.jar &
# 终端断开也不死(但上一课说了,生产请用 systemd)
nohup java -jar app.jar > app.log 2>&1 &
disown # 从终端任务列表移除,彻底脱离
步骤 6:进程优先级——nice 与 renice
# 启动时指定优先级:nice 值 -20(最高)到 19(最低),默认 0
nice -n 10 tar czf backup.tar.gz /var/lib/mysql # 备份任务压低优先级,别影响业务
# 调整运行中进程的优先级
renice -n 5 -p 1234
sudo renice -n -5 -p 1234 # 调高优先级(负值)需要 root
实战:磁盘备份、日志压缩这类批处理任务,一律 nice -n 19 起步,避免和 Nginx/MySQL 抢资源。
步骤 7:实战演练——排查本站 CPU 告警
# 1. 确认负载
uptime # load 12.5,4 核,过载 3 倍
# 2. 找元凶
top # 按 P 排序,发现 java 进程 %CPU 380%
# 3. 定位到线程(Java 特有,面试加分)
top -H -p $(pgrep -f codeforge.jar) # -H 显示线程,找到最忙的线程 PID 12345
# 4. 转换线程号为十六进制,去 jstack 里找
printf "%x\n" 12345 # 输出 3039
jstack $(pgrep -f codeforge.jar) | grep -A 20 "nid=0x3039"
# 看到线程栈:某个导出功能在循环拼接字符串 → 定位到代码
# 5. 临时缓解
renice -n 10 -p $(pgrep -f codeforge.jar) # 降优先级
# 根治:修复代码后重启
讲清楚要点
- load average 包含 D 状态进程:它统计的是「运行中 + 等 CPU + 等磁盘 I/O」的进程总数。所以磁盘坏了时 load 会飙高但 CPU 很闲——看 load 必须配合 %Cpu 的 wa 值。
- load ÷ 核数才是利用率:单看 load 8.0 没意义,8 核机器刚刚好,2 核机器已崩溃。
nproc查核数。 - %CPU 可以超过 100%:多线程进程会占多个核,400% 表示吃满 4 个核。top 里按
1展开每核视图看得更清楚。 - 僵尸进程(Z)杀不死:它已经是尸体,
kill -9无效。解法是让父进程收尸(重启父进程),或父进程退出后由 systemd(PID 1)领养回收。 - D 状态进程也不能 kill:它在等内核 I/O 返回,信号送不进去。只能等 I/O 完成或修复底层存储(如 NFS 挂载卡死时 umount -f)。
- SIGTERM 是礼貌,SIGKILL 是暴力:永远先 TERM 再 KILL。给应用留 10~30 秒执行停机钩子(Spring Boot 默认支持优雅停机,配
server.shutdown=graceful)。 ps aux是快照,top是直播:写脚本抓数据用 ps,人工盯盘用 top/htop。
你可能会懵的地方
-
load 很高但 CPU 空闲率(id)也很高,为什么? 典型 I/O 瓶颈:大量进程在 D 状态等磁盘。load 把它们也算进去了。看
%Cpu行的 wa(iowait)确认,超过 20% 就要查磁盘。 -
僵尸进程会占内存吗? 几乎不占。它只剩一个进程表条目(PID、退出码),所有内存和文件句柄都已释放。危害是占满 PID 号段(默认上限 32768),导致无法 fork 新进程。
-
为什么
kill 1234后进程还在? 进程可以捕获并忽略 SIGTERM(比如正在执行关键事务)。等 10~30 秒;还不退检查是否在 D 状态;最后才 -9。 -
ps aux里的 VSZ 和 RSS 看哪个? RSS(常驻内存)是实际占用的物理内存,看这个。VSZ 是虚拟地址空间,Java 应用 VSZ 经常几十 GB 但没关系。 -
Ctrl+C 和 kill -9 效果一样吗? 不一样。Ctrl+C 发 SIGINT(可捕获,相当于礼貌打断);kill 默认 SIGTERM;kill -9 才是 SIGKILL。三者强度递增。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
上来就 kill -9 | 数据丢失、连接泄漏、MySQL 崩溃恢复 | 先 kill(TERM),等 10~30 秒再 -9 |
pkill java 想杀一个应用 | 杀掉服务器上所有 Java 进程 | pkill -f "codeforge.jar" 精确匹配 |
| 看 load 5.0 就报警 | 不知道机器几核 | nproc 看核数,load/核数 才是负载率 |
| 备份任务直接跑 | 和业务抢 I/O,接口超时 | nice -n 19 ionice -c3 tar czf ... |
nohup ... & 后关终端发现进程没了 | 忘了 disown 或输出重定向 | nohup cmd > out.log 2>&1 & disown |
| top 里看到 java 就重启 | 没定位是哪个 jar | 按 c 显示完整命令行确认目标 |
卡点急救
-
现象:top 里一堆僵尸进程(Z)越来越多 父进程没有 wait 收尸,是父进程的 bug。解决:
ps aux | awk '$8 ~ /Z/ {print $2}'列出僵尸 →ps -o ppid= -p 僵尸PID找父亲 → 重启父进程统一收尸。 -
现象:
kill -9都杀不掉的进程 进程在 D 状态(不可中断睡眠),信号进不去。解决:查它在等什么(通常是 NFS/磁盘),cat /proc/PID/wchan;修复底层 I/O 或强制卸载卡死的挂载点。 -
现象:服务器整体变慢,但 top 里看不出单个高占用进程 可能是大量短生命周期进程(如疯狂 fork 的脚本)或 I/O 瓶颈。解决:
vmstat 2看 r 列(运行队列)和 cs(上下文切换);iostat -x 2看磁盘。
面试常问
-
load average 三个数字是什么意思?多少算高? 1 分钟、5 分钟、15 分钟的平均负载,统计运行中(R)加不可中断睡眠(D)的进程数。判断标准:load ÷ CPU 核数,持续大于 1 说明饱和,大于 2 需要立即排查。还要看趋势:1 分钟值远高于 15 分钟值 = 负载在恶化。
-
kill 和 kill -9 的区别? kill 默认发 SIGTERM(15),进程可捕获并优雅退出(关闭连接、刷盘、执行停机钩子);kill -9 发 SIGKILL,内核直接终结进程,不给任何清理机会。生产环境先 TERM 后 KILL,MySQL 等数据库被 -9 后需要崩溃恢复。
-
什么是僵尸进程?怎么清理? 子进程已退出但父进程没有调用 wait() 读取退出码,留下进程表条目。状态为 Z,kill 无效。清理方法:找到父进程(
ps -o ppid= -p 僵尸PID),重启父进程;或杀死父进程后由 PID 1 领养回收。根因是父进程代码缺陷。
自测三问
- 4 核服务器 load average 是
8.0, 4.0, 2.0,说明什么?下一步看什么指标? - 如何找到并杀掉名为
codeforge.jar的 Java 进程(要求不误杀其他 Java 进程)? - top 的 %Cpu 行中 wa 达到 45%,说明什么瓶颈?用什么命令进一步确认?
小结一句话
进程排查三步走——uptime 看负载、top 找大户、kill 先礼后兵;记住 load 要除核数、wa 高是磁盘锅、-9 永远是最后手段。
延伸
- Linux 进程管理 — man ps/top/kill
- Understanding Linux Load Average(Brendan Gregg 经典文章)
- 下一课:磁盘与文件系统——df/du 查空间、挂载、LVM 与磁盘满了的急救。