原标题:进程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 调回来看输出。


一个程序到底是怎么“运行起来”的

大致流程:

  1. fork:你在shell里敲下命令回车,shell调用 fork() 系统调用,复制出一个和自己几乎一模一样的子进程(这个子进程此时PPID就是shell的PID)。
  2. exec:这个子进程立刻调用 exec() 系列系统调用,把自己的内存空间替换成你要运行的程序的代码(比如 /usr/bin/vim),PID不变,但程序内容整个换掉了。
  3. 内核分配资源:内核给这个进程分配独立的虚拟内存空间、文件描述符表(默认0/1/2对应stdin/stdout/stderr)、调度到CPU时间片上开始执行。
  4. 运行:进程在用户态执行指令,需要系统资源(读写文件、网络、内存分配)时通过系统调用陷入内核态处理。
  5. 退出:程序执行完 main 函数返回,或者调用 exit(),内核回收它占用的大部分资源,但会保留一个退出状态码,直到父进程通过 wait()/waitpid() “收尸”(否则就变成僵尸进程 Z 状态)。
  6. 孤儿进程:如果父进程先于子进程退出,子进程会被 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。