kill -9 是很多人的肌肉记忆——进程不听话,直接 -9 送走。但 kill 这个命令名其实起得有误导性:它默认发的信号根本不是”杀死”,而是”请求退出”。这两者的区别,决定了进程退出前有没有机会保存数据、释放资源。

这是 Linux 命令系列的一篇,承接 Linux 常见命令与工具地图服务器排查那篇 讲了用 ps/top 找进程,这篇讲找到之后怎么正确地”管”它。

信号:内核给进程递的通知条

信号(signal)是内核发给进程的一种异步通知。大部分信号进程可以选择怎么响应——捕获它执行自定义逻辑、忽略它、或者按默认行为处理;只有极少数信号(比如 SIGKILL)是强制的,进程没有任何选择余地。

1
2
3
kill -l
# 列出系统支持的全部信号,有几十个
# 日常真正需要认识的只有三四个:TERM、KILL、HUP

kill 命令的作用就是给指定 PID 的进程发信号——发什么信号由参数决定,不指定就发默认的。

SIGTERM(15):kill 的默认信号,请求优雅退出

1
2
3
4
5
6
7
8
kill 12345
# 不带任何信号参数,默认发 SIGTERM(15)
# 语义是"请你退出"——进程可以捕获这个信号,先做完清理再退出:
# 保存未写盘的数据、关闭数据库连接、写完最后的日志

kill -15 12345
kill -TERM 12345
# 和上面完全等价,显式写出信号编号或名字

绝大多数正经写的服务都注册了 SIGTERM 处理逻辑(Go 里的 signal.Notify、容器里的优雅停机钩子都是响应它),收到后会体面地收尾。这也是 systemctl stopdocker stop 停服务时先发的信号。

SIGKILL(9):最后手段,不是首选

1
2
3
kill -9 12345
# SIGKILL 由内核直接终结进程,进程无法捕获、无法忽略——
# 也就没有任何清理机会:没保存的数据直接丢、锁文件残留、连接不释放

-9 的问题不在”杀不死”,恰恰在”杀得太死”:进程的清理逻辑一行都不会执行。数据库进程被 -9 可能留下损坏的数据文件,持锁的进程被 -9 可能让别的进程永远等锁。正确的顺序是:

1
2
3
4
5
6
kill 12345
# 第 1 步:先发 SIGTERM,给进程清理的机会

sleep 5 && kill -0 12345 2>/dev/null && kill -9 12345
# 第 2 步:等几秒,确认还没退出(kill -0 只检测进程存在,不发实际信号),
# 这时候再上 -9 强制终结

-9 当默认选项,等于放弃了所有进程善后的机会——它应该是 SIGTERM 无效之后的最后手段。

SIGHUP(1):重载配置的约定俗成

SIGHUP 历史上表示”终端挂断”(hangup,拨号上网时代的遗产),现在大量守护进程把它重新定义成”重新加载配置文件,但不重启”:

1
2
3
kill -HUP $(cat /var/run/nginx.pid)
# 给 nginx 主进程发 SIGHUP,nginx 会重读配置并平滑应用,服务不中断
# nginx -s reload 底层做的就是这件事

不是所有程序都遵守这个约定,用之前查一下目标服务的文档;但见到 kill -HUP 时要知道,它的意图大概率是”重载配置”,不是杀进程。

pkill / pgrep:按名字找和杀,跳过查 PID

pgrep 按进程名查 PID,pkill 按进程名直接发信号——省掉 ps aux | grep xxx 再手动复制 PID 的三步操作:

1
2
3
4
5
6
7
8
9
pgrep -l nginx
# -l:连同进程名一起列出所有匹配 "nginx" 的进程 PID

pkill nginx
# 给所有名字匹配 "nginx" 的进程发 SIGTERM(默认信号和 kill 一样)

pkill -9 -f "python.*worker"
# -f:匹配完整命令行而不只是进程名——适合按启动参数区分同名进程
# 注意 -f 匹配范围大,先用 pgrep -f 确认匹配到的是哪些进程再杀,避免误伤

pkill -f 是双刃剑:模式写宽了会把不相干的进程一起杀掉。安全的习惯是先跑一遍同参数的 pgrep -fl,看清楚列表再动手。

nice / renice:CPU 调度优先级

nice 值决定进程在 CPU 竞争中的优先级,范围 -20 到 19——数值越低优先级越高,这个方向和直觉相反:可以理解成”nice 值越高,进程越’客气’,越愿意把 CPU 让给别人”。普通用户只能调高 nice 值(降低优先级),设负值需要 root。

1
2
3
4
5
6
7
nice -n 19 tar -czf backup.tar.gz /data
# -n:指定 nice 值增量,19 是最低优先级
# 跑大型备份、压缩这类不着急的任务时降低优先级,避免拖慢正常服务

renice -n 10 -p 12345
# renice 调整已经在运行的进程,-p 指定 PID
# 发现某个后台任务吃 CPU 影响了在线服务,不用重启它,直接调低优先级

常用命令速查表

命令/信号 作用
kill PID 发默认信号 SIGTERM(15),请求优雅退出
kill -9 PID SIGKILL,内核强制终结,无清理机会,最后手段
kill -HUP PID 多数守护进程约定为”重载配置不重启”
kill -0 PID 不发实际信号,只检测进程是否存在
kill -l 列出全部信号
pgrep -l 名字 按进程名查 PID
pkill 名字 按进程名发 SIGTERM
pkill -f 模式 按完整命令行匹配,先用 pgrep -fl 确认再杀
nice -n N 命令 以指定优先级启动,-20 最高、19 最低,越低越优先
renice -n N -p PID 调整运行中进程的优先级,负值需要 root

写到这里

kill 家族的正确打开方式:默认 SIGTERM 给进程体面退出的机会,几秒后还赖着不走再 -9;重载配置认准 SIGHUP;批量操作用 pkill 但先 pgrep 确认目标。至于 nice,记住”值越低越优先”这个反直觉设定,剩下的就是两条命令的事。