LinuxNotes

第 07 章:进程与作业

zjc 于 2026-01-07 发布

这是《Linux 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 进程是 Linux 资源分配的基本单位。服务为什么启动失败、CPU 为什么高、进程为什么退出、僵尸进程从哪里来,都需要从进程状态、父子关系、环境和信号入手。

7.1 进程基础

查看进程:

ps aux
ps -ef
ps -eo pid,ppid,user,stat,%cpu,%mem,etime,cmd --sort=-%cpu
ps -p <pid> -o pid,ppid,user,stat,cmd

动态观察:

top
htop

进程树:

pstree -ap
pstree -ap -s <pid>

进程关键属性:

属性 含义
PID 进程 ID
PPID 父进程 ID
UID 运行用户
STAT 状态
%CPU CPU 使用率
%MEM 物理内存占比
nice 调度优先级
cmdline 启动命令

7.2 进程状态

ps 常见状态:

状态 含义
R 运行或等待 CPU
S 可中断睡眠
D 不可中断 IO 等待
Z 僵尸进程
T 暂停
I 空闲内核线程

附加位:

含义
s 会话首进程
l 多线程
+ 前台进程组
< 高优先级
N 低优先级

D 状态常见于 IO 或存储异常,通常不能被普通信号杀死。大量 D 状态要检查磁盘、文件系统和内核日志。

7.3 查看进程详情

cat /proc/<pid>/status
cat /proc/<pid>/cmdline
cat /proc/<pid>/environ
ls -l /proc/<pid>/cwd
ls -l /proc/<pid>/exe
ls -l /proc/<pid>/fd
cat /proc/<pid>/limits
cat /proc/<pid>/io

示例:

tr '\0' '\n' < /proc/<pid>/environ | grep JAVA_HOME
readlink -f /proc/<pid>/cwd
readlink -f /proc/<pid>/exe

排查要点:

  1. 进程到底在哪里运行;
  2. 使用哪个二进制;
  3. 环境变量是否正确;
  4. 打开了哪些文件;
  5. 限制是否足够。

7.4 前台、后台与作业

启动后台任务:

./server &

查看作业:

jobs -l

切换:

fg %1
bg %1

暂停:

Ctrl+Z

脱离当前终端继续运行:

nohup ./server > server.log 2>&1 &
disown -h %1

生产服务不要长期用 nohup 管理,应使用 systemd 或容器编排。

7.5 信号

查看信号:

kill -l

常用信号:

信号 数字 含义
SIGHUP 1 挂起,也常用于重载配置
SIGINT 2 中断,通常是 Ctrl+C
SIGQUIT 3 退出并可能生成 core
SIGTERM 15 正常终止,推荐
SIGKILL 9 强制杀死
SIGSTOP 19 暂停
SIGCONT 18 继续

发送信号:

kill <pid>
kill -15 <pid>
kill -TERM <pid>
kill -9 <pid>
pkill -TERM -f 'java -jar app.jar'
killall -TERM nginx

优先顺序:

SIGTERM
  -> 等待应用清理并退出
     -> 超时后 SIGKILL

不要一上来就 kill -9,否则可能丢数据、留下锁或半写状态。

7.6 退出与等待

查看退出码:

true
echo $?
false
echo $?

常见退出码:

退出码 含义
0 成功
1 常见通用错误
2 命令用法错误
126 无权限执行
127 命令不存在
130 Ctrl+C 中断
137 通常对应 SIGKILL,128 + 9
143 通常对应 SIGTERM,128 + 15

脚本判断:

command || exit 1
command && echo OK

7.7 僵尸进程

僵尸进程是已经退出,但父进程尚未回收退出状态的进程。

查找:

ps -eo pid,ppid,stat,cmd | awk '$3 ~ /^Z/'

处理:

  1. 修复父进程的资源回收逻辑;
  2. 父进程可响应时重载或重启;
  3. 孤儿进程通常由 init / systemd 收养并自动回收。

僵尸本身不占用大量内存,但大量堆积说明父进程实现有问题。

7.8 进程优先级

查看:

nice -n 10 ./batch-job
renice -n 10 -p <pid>
ionice -c2 -n7 -p <pid>

取值范围和默认值与系统实现有关。普通用户通常只能降低自己的优先级,即数值变大。

批处理任务建议:

nice -n 19 ionice -c2 -n7 ./batch-job

避免离线任务和在线服务抢占关键资源。

7.9 /proc 与 cgroup 视角

查看 cgroup:

cat /proc/<pid>/cgroup
ls /sys/fs/cgroup

查看服务归属:

systemctl status <service>
systemctl show <service> -p MainPID -p Cgroup

容器中常见两个视角:

视角 命令 说明
宿主机全局 ps aux 看到所有进程
容器 namespace docker top <container> 或容器内 ps 看到容器内视图

排查 Java 应用 CPU 高时,要区分是容器限流还是宿主机整体繁忙。

7.10 常见故障

启动失败

systemctl status app
journalctl -u app -n 200 --no-pager
systemctl cat app
cat /proc/$(systemctl show -p MainPID --value app)/limits 2>/dev/null

常见原因:

  1. 二进制不存在或无执行权限;
  2. 配置文件权限错误;
  3. 端口占用;
  4. 用户或目录错误;
  5. 环境变量缺失;
  6. 文件数或进程数限制;
  7. 应用自身校验失败。

进程消失

journalctl -u app --since '1 hour ago'
dmesg -T | grep -Ei 'oom|killed process'
systemctl show app -p ExecMainStatus -p Result

OOM:

内核根据内存压力选择牺牲进程
  -> dmesg 出现 Out of memory
     -> 进程退出码可能是 137

CPU 高

top -H -p <pid>
ps -T -p <pid>
pidstat -t -p <pid> 1

先定位线程,再转换为应用线程栈。Java 可结合 jstack 分析。

本章小结

进程管理要理解 PID、PPID、状态、环境、打开文件、信号和退出码。生产终止流程应优先 SIGTERM,等待应用清理,超时后再 SIGKILL。服务长期运行应交给 systemd 或容器编排,而不是 nohup

思考题

  1. D 状态和 R 状态分别说明什么问题?
  2. kill -15kill -9 的核心差异是什么?
  3. 退出码 137 和 143 通常代表什么?
  4. 僵尸进程的根因在哪里?
  5. 服务启动失败时,你会按什么顺序收集证据?