原标题:进程PID / PPID
Linux 文件系统是在讲数据怎么存
进程(Process)就是在讲程序怎么活着运行
可执行文件
│
▼
./nginx
│
▼
内核创建进程(Process)
│
▼
获得 PID
│
▼
CPU 调度运行
│
▼
结束(exit)
一、进程基础概念:程序(Program)和进程(Process)的区别
程序(Program):即文件
进程(Process):运行后的程序
程序 = 图纸
进程 = 正在工作的机器
PID / PPID
每个运行中的程序都是一个进程(process)
PID(Process ID)是每个进程唯一的编号。
PPID(Parent Process ID)是这个进程的“父进程”的PID。
Linux里进程是树状结构:init/systemd(PID 1)是所有进程的祖先,你在终端敲命令时,shell(比如bash)会 fork 出一个子进程去执行这个命令,这个子进程的PPID就是shell的PID。
用 ps -ef 或 pstree 能看到这种父子关系:
systemd(1)
└─ bash(2381)
└─ vim(2450)
PID 1 为什么特殊
Linux 开机以后。内核启动完成。第一个用户态程序就是systemd
systemd
它永远都是
PID = 1
所有其他进程最终都来自它。
systemd
│
├── sshd
│ └── bash
│ └── python
│
└── nginx
如果父进程退出了,子进程会被 PID 1 接管(收养)。
守护进程daemon 和 service
daemon(守护进程)【一直在后台运行,不需要人操作。】是指没有控制终端、在后台常驻运行的进程,通常名字以 d 结尾。
比如 sshd(SSH守护进程)、crond(定时任务守护进程)、nginx(worker模式下也是常驻后台)。
它们的特点是:脱离终端、通常PPID是1(被systemd直接管理或被孤儿后重新收养)、长期运行、处理请求或监听端口。
service 是更上层的管理概念,尤其在现代Linux里指 systemd unit。你用 systemctl start nginx 启动的其实就是让systemd去拉起nginx这个daemon进程,并负责它的生命周期管理(开机自启、崩溃重启、日志收集等)。
简单说:daemon是“跑起来的那个进程”,service是“systemd对这个daemon的管理封装”。
这些命令之间的关系
systemd (PID 1)
│
管理各种 daemon/service
│
┌──────────────┴──────────────┐
│ │
nginx sshd
│
bash (Shell)
│
输入命令:python app.py
│
fork() + execve()
│
python (PID 4321)
│
┌───────────────┬─────────────┴─────────────┐
│ │ │
ps/top/htop kill/killall jobs/bg/fg
查看系统进程 向进程发送信号 管理当前 Shell 的作业
掌握了这套模型后,再学习 fork()、execve()、信号(signal)、僵尸进程(Zombie)、孤儿进程(Orphan)、线程(Thread)和 /proc 文件系统,就能比较完整地理解 Linux 的进程管理机制。
常用命令
ps
查看进程快照(某一时刻的状态),最常用组合:
ps aux # BSD风格,显示所有用户的所有进程
ps -ef # System V风格,带PPID,方便看父子关系
ps aux | grep nginx # 找特定进程
ps aux 输出的关键列:PID、%CPU、%MEM、STAT(进程状态,如R运行、S睡眠、Z僵尸)、COMMAND。
top / htop
top 是实时刷新的进程监控器,默认按CPU占用排序,可以按 M 切换按内存排序,按 q 退出。它是系统自带的,几乎所有Linux发行版都有。
htop 是top的增强版(需要单独安装 apt install htop / yum install htop),界面更友好:彩色、可以鼠标点击、能直接用方向键选中进程后按 F9 发送信号杀掉,还能看每个CPU核心的占用条形图。功能上是超集,唯一缺点是不一定默认安装。
kill / killall
kill 是按PID给进程发信号,注意“kill”这个名字有点误导——它本质是发信号,不一定是杀死:
kill 1234 # 默认发SIGTERM(15),礼貌地请求进程退出,可被进程捕获后自行清理
kill -9 1234 # SIGKILL,强制立即终止,进程无法捕获或忽略,内核直接收
kill -HUP 1234 # SIGHUP,很多daemon用它触发"重新加载配置"而不是退出
killall 按进程名而非PID来发信号,会杀掉所有同名进程:
killall nginx # 杀掉所有叫nginx的进程
killall -9 python
jobs / bg / fg
这三个是shell的作业控制(job control),管理当前终端里通过这个shell启动的任务。
- 你在终端跑一个命令后按
Ctrl+Z,会把它暂停并放到后台,返回shell提示符。 jobs列出当前shell管理的所有作业(及其编号[1],[2]…)。bg %1让1号作业在后台继续运行(但仍占用这个终端会话)。fg %1把1号作业调回前台,重新接管终端的输入输出。
这套东西和 &(命令后加&直接后台启动)配合使用非常常见,比如 long_task & 然后用 jobs 查看、fg 调回来看输出。
一个程序到底是怎么“运行起来”的
大致流程:
- fork:你在shell里敲下命令回车,shell调用
fork()系统调用,复制出一个和自己几乎一模一样的子进程(这个子进程此时PPID就是shell的PID)。 - exec:这个子进程立刻调用
exec()系列系统调用,把自己的内存空间替换成你要运行的程序的代码(比如/usr/bin/vim),PID不变,但程序内容整个换掉了。 - 内核分配资源:内核给这个进程分配独立的虚拟内存空间、文件描述符表(默认0/1/2对应stdin/stdout/stderr)、调度到CPU时间片上开始执行。
- 运行:进程在用户态执行指令,需要系统资源(读写文件、网络、内存分配)时通过系统调用陷入内核态处理。
- 退出:程序执行完
main函数返回,或者调用exit(),内核回收它占用的大部分资源,但会保留一个退出状态码,直到父进程通过wait()/waitpid()“收尸”(否则就变成僵尸进程 Z 状态)。 - 孤儿进程:如果父进程先于子进程退出,子进程会被 PID 1(systemd)收养,PPID变成1。
这就是为什么 ps -ef 里几乎所有daemon的PPID都是1——它们要么是systemd直接fork+exec起来的,要么是启动后父进程退出被systemd收养了。
注意
kill -9是强制杀死,进程没机会做清理(比如关闭数据库连接、保存缓存),容易导致数据不一致或临时文件残留,一般应先尝试普通kill(SIGTERM),等几秒不行再上9。killall按名字匹配,如果机器上同名的进程不止你以为的那一个(比如多个用户都跑了python),可能会误杀别人的进程,生产环境建议先用pgrep -a 进程名确认清单再动手。- 直接对系统关键daemon(如
systemd、sshd本身的主进程)执行kill -9可能导致服务瞬间不可用甚至系统异常,生产环境优先用systemctl stop/restart而不是手动kill。
如果这篇文章对你有帮助,点个赞吧。

