← 返回 Linux命令图解 目录
🔄 Linux进程管理图解
进程状态/信号/systemd/前台后台/top命令 · SVG可视化 + 生活类比
① 进程状态与转换
把进程想象成公司里的员工:
• Running = 在岗工作(正在使用CPU干活)
• Ready = 待命等待(准备好了,等CPU调度)
• Sleeping = 休息等待(等IO完成/等用户输入/等定时器)
• Zombie = 僵尸(离职了但没交接!进程已结束,父进程还没收走退出码)
• Stopped = 停工(被老板叫停/被信号暂停)
进程5种状态及转换:在岗/待命/休息/僵尸/停工
僵尸进程(Zombie)是生产环境常见问题!进程exit后变成Z状态,PID和退出码还留着。如果父进程不调用wait()收尸,僵尸会一直占PID。大量僵尸→PID耗尽→无法创建新进程。
排查:`ps aux | grep Z` 找到僵尸,然后 `kill -9 父进程PID` 让init接管并回收。
② 进程管理命令
进程管理三大类命令:查看/控制/后台
# 查看所有Java进程
$ ps aux | grep java
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
app 12345 15.2 8.1 4567890 523456 ? Sl Jun10 123:45 java -jar app.jar
app 12346 0.0 0.0 11234 2345 pts/0 S+ 10:20 0:00 grep java
# 查看进程树(看父子关系)
$ ps -ef --forest
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Jun10 ? 00:00:15 /sbin/init
root 234 1 0 Jun10 ? 00:00:05 /usr/sbin/sshd
root 1234 234 0 Jun10 ? 00:00:03 sshd: app
app 1235 1234 0 Jun10 pts/0 00:00:00 -bash
app 12345 1235 2 Jun10 pts/0 00:12:34 java -jar app.jar
# top关键指标解读
$ top -p 12345 # 只监控特定进程
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
12345 app 20 0 4567m 523m 12m S 15.2 8.1 123:45 java
# ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
# PID 优先级 虚拟内存 物理内存 共享 状态 CPU 内存占比
top常用交互命令:按 `M` 按内存排序,按 `P` 按CPU排序,按 `1` 看每个CPU核心,按 `c` 显示完整命令行,按 `k` 杀进程。
③ 前台/后台/守护进程
前台进程 = 接待处员工(你看得见,终端关了就下班)
后台进程 = 仓库员工(你看不见,但还在干活,终端关了也会走)
守护进程(Daemon) = 保安(永远在,不受终端影响,系统启动就在)
关键区别:前台/后台进程都绑定终端,终端关了进程就死。守护进程不绑定任何终端,用nohup可以让普通进程"假装"守护。
三种进程类型:前台(接待) vs 后台(仓库) vs 守护(保安)
# ❌ 错误方式:直接后台运行
$ java -jar app.jar &
# 问题:关掉终端后进程会收到SIGHUP然后死掉
# ✅ 正确方式1:nohup + &
$ nohup java -jar app.jar &
# nohup:忽略SIGHUP信号
# &:后台运行
# 输出默认重定向到nohup.out
# ✅ 正确方式2:nohup + 自定义日志
$ nohup java -jar app.jar > app.log 2>&1 &
# > app.log 标准输出到文件
# 2>&1 标准错误也到同一文件
# & 后台运行
# ✅ 正确方式3:systemd服务(生产推荐)
$ sudo systemctl start my-app
$ sudo systemctl enable my-app # 开机自启
④ systemd服务管理
systemd = 公司的行政管理系统:员工(服务)上班打卡、考勤记录、请假审批。
• systemctl start = 叫员工来上班
• systemctl stop = 让员工下班
• systemctl enable = 设为正式员工(每天自动来)
• systemctl status = 查员工考勤记录
• journalctl = 查员工工作日志
/etc/systemd/system/my-app.service
[Unit]
Description=My Spring Boot Application
After=network.target mysql.service # 网络和MySQL就绪后再启动
[Service]
Type=simple # 主进程就是服务进程
User=app # 用app用户运行
WorkingDirectory=/opt/my-app
ExecStart=/usr/bin/java -jar /opt/my-app/app.jar
ExecStop=/bin/kill -SIGTERM $MAINPID
Restart=on-failure # 挂了自动重启
RestartSec=10 # 10秒后重启
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target # 多用户模式下启动
$ # 常用systemctl命令
sudo systemctl daemon-reload # 改了service文件后重新加载
sudo systemctl start my-app # 启动
sudo systemctl stop my-app # 停止
sudo systemctl restart my-app # 重启
sudo systemctl enable my-app # 开机自启
sudo systemctl status my-app # 查看状态+最近日志
$ # journalctl查看日志
sudo journalctl -u my-app # 该服务所有日志
sudo journalctl -u my-app -f # 实时跟踪(tail -f)
sudo journalctl -u my-app --since today # 今天的日志
sudo journalctl -u my-app -n 50 # 最近50行
⑤ 信号机制
信号 = 不同级别的通知:
• SIGHUP(1) = 电话通知(终端关闭时发,"你的工位要关了")
• SIGINT(2) = 敲门通知(Ctrl+C,"请停下手中的活")
• SIGTERM(15) = 正式通知信(kill默认,"请优雅地结束")
• SIGKILL(9) = 强制驱逐令(kill -9,"立刻走,不给收拾东西")
• SIGSTOP = 暂停令("先停一下")
• SIGCONT = 继续令("继续干活")
| 信号 | 编号 | 类比 | 能否被捕获 | 典型场景 |
| SIGHUP | 1 | 电话通知 | ✅ 能 | 终端关闭/配置重载 |
| SIGINT | 2 | 敲门通知 | ✅ 能 | Ctrl+C中断 |
| SIGTERM | 15 | 正式通知信 | ✅ 能 | kill默认/优雅关闭 |
| SIGKILL | 9 | 强制驱逐令 | ❌ 不能 | kill -9/最后手段 |
| SIGSTOP | 19 | 暂停令 | ❌ 不能 | Ctrl+Z/调试 |
| SIGCONT | 18 | 继续令 | ✅ 能 | 恢复暂停的进程 |
生产环境不要轻易用 kill -9!
• kill -9 是SIGKILL,进程无法捕获,连finally块都不执行
• 可能导致:临时文件没清理、数据库连接没释放、消息没确认
• 正确做法:先 `kill PID`(SIGTERM),等10-30秒,如果还在才 `kill -9`
• Spring Boot的graceful shutdown就是捕获SIGTERM,处理完当前请求再退出
⑥ 面试速答
什么是僵尸进程?怎么产生的?怎么处理?
定义:子进程exit后,父进程没有调用wait()回收,子进程变成Z状态。
产生:子进程exit → 内核保留PID和退出码 → 父进程不wait → 僵尸
危害:占PID号,大量僵尸→PID耗尽→无法创建新进程
处理:
1. `ps aux | grep Z` 找到僵尸
2. `kill -9 父进程PID` 让init接管并wait
3. 代码层面:父进程用wait()/waitpid()或注册SIGCHLD处理
kill和kill -9有什么区别?
kill PID:发SIGTERM(15),进程可以捕获,做清理工作后优雅退出。
kill -9 PID:发SIGKILL(9),进程无法捕获或忽略,内核直接终止。
类比:kill是"请收拾东西离开"(你可以收拾完再走),kill -9是"保安直接把你拖走"(来不及收拾)。
nohup和&的区别?为什么需要nohup?
&:让命令在后台运行,释放终端。但进程仍然绑定终端。
nohup:让进程忽略SIGHUP信号(终端关闭时发的信号)。
区别:
- `cmd &` → 后台运行,但终端关闭时收到SIGHUP会死
- `nohup cmd &` → 后台运行 + 忽略SIGHUP,终端关闭也不会死
生产环境推荐:用nohup或更好的,用systemd管理服务。
top命令里VSZ和RSS有什么区别?
VSZ(VIRT):虚拟内存大小,进程"认为"自己有多少内存。包含:申请但未使用、共享库、swap等。通常远大于实际使用。
RSS(RES):物理内存大小,进程实际占用的RAM。这才是真正消耗的内存。
类比:VSZ=你申请的办公面积(可能有些区域空着),RSS=你实际在用的工位。
排查内存问题时看RSS,不要看VSZ。
什么是孤儿进程?和僵尸进程有什么区别?
孤儿进程:父进程先死了,子进程还在运行。init(PID=1)会接管这些孤儿,所以孤儿进程不会有问题。
僵尸进程:子进程死了,但父进程还活着且不wait()回收。子进程变成Z状态占用PID。
关键区别:孤儿是被init接管的好孩子,僵尸是父进程不管的坏孩子。
systemd的Restart=on-failure和always有什么区别?
on-failure:只有非正常退出(非0退出码/信号终止/超时)才重启。正常exit(0)不重启。
always:无论什么原因退出都重启,包括正常退出。
选哪个?
- 一般应用用on-failure(正常退出=有意的,不需要重启)
- 关键服务用always(无论如何都要在)
- 注意:always可能导致应用想正常退出但不断重启的死循环
如何查看某个端口被哪个进程占用了?
方法1:`lsof -i :8080` — 列出占用8080端口的进程
方法2:`netstat -tlnp | grep 8080` — 网络统计中过滤
方法3:`ss -tlnp | grep 8080` — 更快的netstat替代
方法4:`fuser 8080/tcp` — 直接显示PID
推荐用ss替代netstat(更快更现代),lsof最详细。
nice值和优先级是什么关系?
nice值:-20到19,-20最高优先级,19最低。默认0。
关系:PR(优先级) = NI(nice) + 20。nice越低→优先级越高→分到更多CPU时间。
类比:nice值=工龄,工龄长的员工(nice低)在食堂排队优先打饭。
注意:普通用户只能调高nice值(降低优先级),root才能调低nice值(提高优先级)。
核心三原则速记
进程管理三原则:① 先 top/htop 看全貌,再 ps 精确定位 → ② kill -15 优雅退出,kill -9 是最后手段(不释放资源) → ③ 僵尸进程(Z状态)是父进程没收尸,杀父进程才能清理