进程与信号:kill -9 为什么是最后手段
进程挂了、杀不死、CPU 跑满——这些问题的解法都建立在「理解信号」之上。
一、进程状态怎么读
ps aux
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
# ↑
# STAT 是状态位| 状态 | 含义 |
|---|---|
| R | Running,正在运行或可运行 |
| S | Sleeping,可中断睡眠(等事件) |
| D | 不可中断睡眠(多在等磁盘/网络 IO) |
| T | Stopped,被暂停(Ctrl+Z 或 SIGSTOP) |
| Z | Zombie,僵尸进程 |
| I | Idle,内核线程空闲 |
附加标记:< 高优先级、N 低优先级、s 会话组长、+ 前台进程组。
看到一堆
D状态,通常说明磁盘或 NFS 卡住了,这时候kill -9也杀不掉,得先解决底层 IO。
二、信号:kill 发的到底是什么
kill 名字有误导性,它其实是「发信号」:
| 信号 | 编号 | 默认行为 | 说明 |
|---|---|---|---|
| SIGHUP | 1 | 终止 | 终端断开。很多程序会重新加载配置 |
| SIGINT | 2 | 终止 | Ctrl+C |
| SIGQUIT | 3 | 终止+core | Ctrl+\ |
| SIGKILL | 9 | 终止 | 不可被捕获,强制杀死 |
| SIGTERM | 15 | 终止 | 默认信号,程序可优雅退出 |
| SIGSTOP | 19 | 暂停 | 不可被捕获 |
| SIGCONT | 18 | 继续 | 恢复被暂停的进程 |
kill -15 <PID> # 或 kill <PID>,默认就是 15
kill -9 <PID> # 强杀,最后手段
kill -HUP <PID> # 让 nginx 等程序重载配置
kill -l # 列出所有信号为什么 -9 是最后手段
SIGTERM 会被程序捕获,它有机会:保存数据、关闭连接、删除临时文件、释放锁。
SIGKILL 直接由内核杀死,程序什么都来不及做,可能留下损坏的数据文件、半写的日志、未释放的锁。
正确顺序:
kill -15 <PID> # 先温柔地请它退出
sleep 5
kill -0 <PID> 2>/dev/null && kill -9 <PID> # 还活着才强杀三、前后台与 nohup
./long-task.sh # 前台运行,Ctrl+C 中断
./long-task.sh & # 后台运行,但终端关闭时仍会被 SIGHUP 杀掉
# nohup:忽略 SIGHUP,输出重定向到文件
nohup ./long-task.sh > task.log 2>&1 &
# 作业控制
jobs # 列出后台作业
fg %1 # 调回前台
bg %1 # 后台继续
Ctrl+Z # 暂停当前前台进程,再用 bg 转后台终端要断开的场景,直接用 tmux 更省心(见「tmux 使用笔记」)。
四、找进程
ps aux | grep nginx
pgrep -a nginx # 直接给 PID + 命令
pkill -f "node server.js" # 按命令行模糊匹配杀掉
pkill -u baize # 杀掉某用户的所有进程
# 看进程树(父子关系一目了然)
pstree -p | head -30
ps -ef --forest | grep nginx
# 看某进程打开了哪些文件/端口
lsof -p <PID>
ls -l /proc/<PID>/cwd # 当前工作目录
cat /proc/<PID>/cmdline | tr "\0" " " # 完整启动命令五、僵尸进程
状态为 Z 的进程已经结束,但父进程没调用 wait() 回收它,于是内核保留了一条记录。
ps aux | awk '$8 ~ /Z/ {print}'
ps -eo stat,ppid,pid,comm | grep -w Z僵尸进程不能被 kill(它已经死了)。两条路:
- 让父进程回收:
kill -CHLD <父PID>,或者等父进程自己处理; - 父进程有 bug 不回收 → 杀掉父进程,僵尸会被 init(PID 1)领养并回收。
少量僵尸无害(只占一个 PID 表项)。大量出现说明父进程有问题,比如没处理 SIGCHLD。
六、CPU 跑满怎么查
# 1. 看是谁
top -c # 按 P 按 CPU 排序,c 显示完整命令
# 2. 看它在干什么
strace -p <PID> # 系统调用
perf top -p <PID> # 函数级热点(需装 linux-tools)
# 3. 多线程程序看每个线程
top -H -p <PID>
ps -L -p <PID> -o pid,tid,pcpu,comm
# 4. Java 应用
jstack <PID> > /tmp/stack.txt七、优先级 nice
nice -n 10 ./backup.sh # 启动时降低优先级
renice -n 5 -p <PID> # 调整运行中进程
ps -eo pid,ni,comm | head范围 -20(最高)到 19(最低),普通用户只能调低不能调高。备份、压缩这类耗时任务设成 10~19,别跟线上服务抢 CPU。
一句话:先 -15,再等 5 秒,最后才 -9。
