进程与信号:kill -9 为什么是最后手段

进程挂了、杀不死、CPU 跑满——这些问题的解法都建立在「理解信号」之上。

一、进程状态怎么读

bash
ps aux
# USER  PID %CPU %MEM  VSZ  RSS TTY STAT START TIME COMMAND
#                            ↑
#                            STAT 是状态位
状态含义
RRunning,正在运行或可运行
SSleeping,可中断睡眠(等事件)
D不可中断睡眠(多在等磁盘/网络 IO
TStopped,被暂停(Ctrl+Z 或 SIGSTOP)
ZZombie,僵尸进程
IIdle,内核线程空闲

附加标记:< 高优先级、N 低优先级、s 会话组长、+ 前台进程组。

看到一堆 D 状态,通常说明磁盘或 NFS 卡住了,这时候 kill -9 也杀不掉,得先解决底层 IO。

二、信号:kill 发的到底是什么

kill 名字有误导性,它其实是「发信号」:

信号编号默认行为说明
SIGHUP1终止终端断开。很多程序会重新加载配置
SIGINT2终止Ctrl+C
SIGQUIT3终止+coreCtrl+\
SIGKILL9终止不可被捕获,强制杀死
SIGTERM15终止默认信号,程序可优雅退出
SIGSTOP19暂停不可被捕获
SIGCONT18继续恢复被暂停的进程
bash
kill -15 <PID>      # 或 kill <PID>,默认就是 15
kill -9 <PID>       # 强杀,最后手段
kill -HUP <PID>     # 让 nginx 等程序重载配置
kill -l             # 列出所有信号

为什么 -9 是最后手段

SIGTERM 会被程序捕获,它有机会:保存数据、关闭连接、删除临时文件、释放锁。 SIGKILL 直接由内核杀死,程序什么都来不及做,可能留下损坏的数据文件、半写的日志、未释放的锁。

正确顺序:

bash
kill -15 <PID>      # 先温柔地请它退出
sleep 5
kill -0 <PID> 2>/dev/null && kill -9 <PID>   # 还活着才强杀

三、前后台与 nohup

bash
./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 使用笔记」)。

四、找进程

bash
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() 回收它,于是内核保留了一条记录。

bash
ps aux | awk '$8 ~ /Z/ {print}'
ps -eo stat,ppid,pid,comm | grep -w Z

僵尸进程不能被 kill(它已经死了)。两条路:

  1. 让父进程回收:kill -CHLD <父PID>,或者等父进程自己处理;
  2. 父进程有 bug 不回收 → 杀掉父进程,僵尸会被 init(PID 1)领养并回收。

少量僵尸无害(只占一个 PID 表项)。大量出现说明父进程有问题,比如没处理 SIGCHLD。

六、CPU 跑满怎么查

bash
# 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

bash
nice -n 10 ./backup.sh       # 启动时降低优先级
renice -n 5 -p <PID>         # 调整运行中进程
ps -eo pid,ni,comm | head

范围 -20(最高)到 19(最低),普通用户只能调低不能调高。备份、压缩这类耗时任务设成 10~19,别跟线上服务抢 CPU。


一句话:先 -15,再等 5 秒,最后才 -9。