一句话总结
系统里每个正在运行的程序都是一个进程(Process),有唯一的 PID.
进程管理的核心就三件事:看谁在跑(ps,top),让它停(kill + 信号),控制它在前台还是后台跑(jobs,bg,fg,nohup).
进程是什么
敲下 python app.py 回车,操作系统就把这段程序装进内存,分配资源,开始执行--这个"正在运行的程序实例"就是一个进程.同一个程序可以同时跑出多个进程(开三个终端各跑一个 python,就是三个进程).
程序(program)是菜谱,进程(process)是按菜谱正在炒的那盘菜.
菜谱只有一份,但可以同时开三个灶台照着它炒三盘--三个进程,互不干扰,各自占用自己的锅和火.
每个进程都带着几个关键身份信息,后面所有命令都围绕它们打转:
| 属性 | 含义 |
|---|---|
PID |
进程 ID,系统内唯一的身份证号,kill 就是靠它定位 |
PPID |
父进程 ID(Parent PID)--谁启动了它 |
UID |
属主用户,决定这个进程有什么权限 |
STAT |
状态:运行中,睡眠,僵尸等 |
%CPU / %MEM |
占用的 CPU 和内存比例,排查"谁把机器拖卡了"靠它 |
进程都有父亲
进程是树状结构:Shell(如 zsh)由终端启动,在 Shell 里跑的命令又以 Shell 为父进程.所有进程往上追溯,最终都挂到 PID 为 1 的 init / systemd 进程上--它是开机后内核启动的第一个进程,是整棵进程树的根.
ps:进程的快照
ps(process status)给出某个瞬间的进程列表--像拍一张照片,不会自动刷新.它的选项历史包袱很重(BSD 风格不带 -,System V 风格带 -),但日常只需要记住两个组合.
ps aux
ps aux
列出系统上所有用户的所有进程,带 CPU / 内存占用.排查"谁在吃资源"的首选.
ps -ef
ps -ef
同样列出所有进程,但额外清晰展示 PPID(父进程),适合理清进程的父子关系.
|
各列含义已在上表覆盖,这里重点看 STAT 列的状态字母:
| 状态 | 含义 |
|---|---|
R |
Running--正在运行或就绪等待 CPU |
S |
Sleeping--可中断睡眠,等待某个事件(绝大多数进程的常态) |
D |
不可中断睡眠,通常卡在磁盘 I/O--连 kill 都打不动它 |
T |
Stopped--被信号暂停(如按了 Ctrl-Z) |
Z |
Zombie--僵尸进程,已结束但父进程还没回收它的退出状态 |
后面可能跟附加符号:s 表示会话首进程,+ 表示在前台进程组,l 表示多线程.
ps 的真正威力来自和管道,grep 组合--这正是前面阶段反复练习的套路:
|
僵尸进程不可怕,进程泄漏才可怕
僵尸(Z)进程本身不占 CPU 和内存,只占一个 PID 槽位,等父进程调用 wait() 回收即可消失.无法 kill 一个僵尸(它已经死了),真正要处理的是它的父进程--父进程退出后,僵尸会被 init/systemd 接管并清理.如果僵尸越积越多,说明父进程写得有 bug,没回收子进程.
top / htop:实时监控
如果说 ps 是照片,top 就是实时录像--它每隔几秒刷新一次,动态展示当前最耗资源的进程.排查"机器突然变卡了"时,第一反应就是敲 top.
|
进入 top 后是交互界面,记住几个高频按键就够用:
| 按键 | 作用 |
|---|---|
P |
按 CPU 占用排序(默认) |
M |
按内存占用排序 |
k |
输入 PID 直接 kill 一个进程 |
q |
退出 |
优先装 htop
htop 是 top 的增强版:彩色,可上下滚动,可用鼠标点选,支持树状视图(F5).brew install htop 或 apt install htop 即可.一旦用过 htop,基本就回不去原版 top 了.
信号:进程间的"敲门方式"
要让一个进程停下来,不是直接"删掉"它,而是给它发一个信号(Signal)--相当于敲门通知它"该收摊了".信号是 Unix 进程间通信的一种轻量机制,内核负责投递.
SIGTERM 是礼貌敲门"忙完请关门走人",进程可以先保存好工作再退出.
SIGKILL 是直接把门拆了把人拖走--立即生效,但进程来不及做任何清理.
常用信号只有几个,重点记住它们的编号和能否被捕获:
| 信号 | 编号 | 含义 | 可被忽略/捕获? |
|---|---|---|---|
SIGTERM |
15 | 礼貌终止,kill 默认发的就是它--给进程清理机会 | 可以 |
SIGKILL |
9 | 强制杀死,立即生效,无法清理 | 不能 |
SIGINT |
2 | 中断,按 Ctrl-C 发的就是它 | 可以 |
SIGHUP |
1 | 挂断--终端关闭时发给子进程,常被守护进程用作"重载配置" | 可以 |
SIGSTOP |
19 | 暂停进程,按 Ctrl-Z 发的是 SIGTSTP(20,可捕获版) | 不能 |
SIGCONT |
18 | 恢复一个被暂停的进程继续运行 | - |
为什么 SIGKILL(9) 和 SIGSTOP(19) 不能被捕获
这两个信号被内核保留为"最终手段"--如果允许进程拦截它们,一个失控或恶意的进程就能让自己永远杀不死,停不下来.所以内核强制规定:9 必杀,19 必停,进程没有任何反抗余地.这也是为什么 kill -9 是"最后的核武器".
kill / pkill / killall:发送信号
kill 的名字有误导性--它不是"杀死",而是"发信号".只是默认发的 SIGTERM 通常会让进程退出,才得名 kill.
|
不要张口就 kill -9
正确顺序是先 kill(SIGTERM)再 kill -9(SIGKILL).SIGTERM 给进程机会保存文件,关闭连接,删除临时文件;kill -9 直接拔电源,可能导致数据损坏,锁文件残留,子进程变孤儿.只有在进程"卡死,SIGTERM 无效"时才动用 -9.
如果不想先查 PID,可以用按名字操作的两个变体:
pkill
pkill [-信号] 进程名模式
按名称模式匹配发送信号,支持部分匹配.pkill -9 python 杀掉所有名字含 python 的进程.
killall
killall [-信号] 精确进程名
按精确名称杀掉所有同名进程.killall nginx 终止全部 nginx 进程.
|
作业控制:前台与后台
一个终端同一时刻只能有一个前台进程占据键盘输入.但常常希望"让这个耗时任务在后台跑,腾出终端干别的"--这就是作业控制(Job Control).
三个关键操作串成一条工作流:
|
| 操作 | 作用 |
|---|---|
命令 & |
启动时直接丢到后台运行,终端立即可用 |
Ctrl-Z |
把当前前台进程暂停并丢到后台(发 SIGTSTP) |
jobs |
列出当前 Shell 管理的后台作业及其编号 |
bg %1 |
让 1 号作业在后台继续运行(恢复被暂停的) |
fg %1 |
把 1 号作业调回前台 |
|
作业号(%1) vs 进程号(PID)
jobs 里的 [1] 是当前 Shell 的作业号,只在这个终端有效,用 %1 引用;PID 是全系统唯一的.fg %1 用作业号,kill 842 用 PID--别混淆.% 还能按名字引用,如 fg %python.
nohup 与 disown:让进程活过终端关闭
后台进程有个致命问题:关闭终端时,Shell 会向它的所有子进程发送 SIGHUP,把它们一起带走.所以单纯 & 放后台还不够--SSH 断线,任务就没了.
解决办法有两类:
|
长任务的现代方案:tmux
nohup / disown 能让进程活下来,但看不到它的实时输出,也无法再交互.更好的方案是用 tmux(第 20 篇)--把任务跑在一个 tmux 会话里,断开 SSH 后会话依然存活,重连后 tmux attach 就能回到现场,输出,交互一个不少.生产环境跑长任务,优先 tmux.
nice 与 renice:调整优先级
当 CPU 紧张时,可以通过 nice 值告诉内核"这个进程不急,先让别人用 CPU".nice 值范围 -20(最高优先级,最不"礼貌")到 19(最低优先级,最"谦让"),默认 0.普通用户只能调高(降低优先级),调低需要 root.
|
nice 值就是进程的"谦让程度"--值越大越谦让(nice,与日常英文同义),主动给别人让 CPU;值越小越霸道,优先抢占 CPU.名字本身就是记忆点.
快速回顾
- 进程 = 运行中的程序实例:由 PID 唯一标识,呈父子树状结构,根是 PID 1 的 init/systemd
- ps aux 拍快照:看所有进程;top / htop 实时监控资源占用--排查卡顿的两大入口
- 信号是进程的"敲门方式":SIGTERM(15) 礼貌退出 · SIGKILL(9) 强制杀死 · SIGINT(2) 即 Ctrl-C · SIGSTOP(19) 暂停
- 9 和 19 无法被捕获:是内核保留的最终手段;杀进程先 kill 再 kill -9,别一上来就 -9
- kill 按 PID · pkill 按模式 · killall 按精确名:动手前先 pgrep 确认目标
- 作业控制:
&后台启动 · Ctrl-Z 暂停 · jobs 列表 · bg 后台继续 · fg 调回前台,作业号用 %1 - nohup / disown 让进程活过终端关闭;长任务更推荐用 tmux
- nice 值(-20~19)调整 CPU 优先级,值越大越"谦让"
动手练习
- CPU/内存大户:用
ps aux | sort -k3 -rn | head找出当前 CPU 占用最高的几个进程,再换成-k4看内存大户 - 实时监控:打开
top(或安装htop),分别按P和M排序,观察哪些进程最耗资源,用q退出 - 作业控制全流程:跑一个
sleep 300,按 Ctrl-Z 暂停,用jobs查看,再用bg转后台,fg调回前台 - 信号实验:启动
sleep 300 &,用kill(SIGTERM)终止它;再启动一个,试试kill -STOP和kill -CONT观察状态变化 - nohup 验证:用
nohup sleep 600 &启动任务后exit关闭终端,重新登录用pgrep -l sleep确认它还活着 - 信号编号:对比
kill -l列出的信号编号,记住 1,2,9,15,18,19 各对应哪个信号