一、什么是进程

进程是计算机上正在运行的程序实例。每个进程都有自己的内存空间、CPU 执行状态、系统资源使用情况和程序计数器。对于操作系统来说,进程是资源分配和调度的基本单位。

一个进程通常包含以下内容:

  • 程序代码
  • 数据段
  • 运行时栈
  • 全局变量
  • 打开的文件描述符
  • 当前运行状态与资源占用信息

1.1 进程与程序的区别

理解进程时,最容易混淆的就是“程序”和“进程”。

  • 程序:存储在磁盘上的可执行文件,本质上是静态的。
  • 进程:程序被加载到内存后处于运行中的实例,本质上是动态的。

也就是说,同一个程序可以同时对应多个进程;这些进程彼此独立,各自拥有自己的进程空间、堆栈和运行状态。

1.2 PID 与 PPID

每个进程都有唯一的进程标识符,称为 PID(Process ID),用于在系统中唯一标识和管理该进程。

除了 PID,每个进程通常还会有:

  • PPID(Parent Process ID):父进程的 PID
  • TTY:关联的终端
  • STAT:当前状态

二、常见进程分类

进程可以根据运行方式和用途分为多种类型,常见分类如下。

2.1 前台进程与后台进程

  • 前台进程(Foreground Process):直接与用户终端交互,接收输入并在当前终端输出结果。
  • 后台进程(Background Process):在后台运行,不直接占用当前终端,通常通过 & 启动。

2.2 守护进程

守护进程(Daemon Process)通常在系统启动时启动,长期在后台运行,用于提供系统服务或执行周期性任务,例如:

  • httpd
  • sshd
  • cron

2.3 父进程与子进程

一个进程可以通过 fork 创建子进程。父进程通常负责启动、管理或等待子进程执行结果,这种关系会形成进程树。

2.4 交互式进程与批处理进程

  • 交互式进程:需要用户实时参与,如编辑器、Shell 命令等。
  • 批处理进程:自动执行、无需实时交互,如备份脚本、定时任务、数据处理任务等。

三、特殊类型进程:僵尸进程与孤儿进程

3.1 什么是僵尸进程

僵尸进程(Zombie Process)是指子进程已经结束,但父进程还没有回收其退出状态,导致该子进程残留在进程表中的一种特殊状态。

僵尸进程的特点:

  • 已经执行结束
  • 基本不再消耗 CPU 与正常内存资源
  • 仍占用一个 PID 和部分进程表信息
  • 如果数量过多,可能影响系统可用进程数

僵尸进程-1

3.1.1 如何查看僵尸进程

方法一:使用 top 查看是否存在僵尸进程,以及僵尸进程数量。

僵尸进程-2

方法二:使用 ps 过滤状态为 Z 的进程。

$ ps aux | grep Z

3.1.2 如何处理僵尸进程

常见处理思路有两种:

  • 如果僵尸进程的父进程不是 PID 1,通常可以找到父进程并结束它,或者让父进程正确回收子进程。
  • 如果僵尸进程异常地长期挂在系统接管进程下,则通常需要进一步排查父进程退出逻辑,必要时重启相关服务或系统。

3.2 什么是孤儿进程

孤儿进程(Orphan Process)是指父进程先退出,但子进程仍在继续运行的进程。孤儿进程会被系统接管,通常由 PID 1 的 initsystemd 负责托管。

孤儿进程本身并不一定有问题,它与僵尸进程最大的区别在于:

  • 孤儿进程仍然活着,还在继续运行。
  • 僵尸进程已经结束,只是退出状态还没有被回收。

孤儿进程

四、演示僵尸进程的产生与排查

4.1 准备模拟环境

先创建一个 zombie.c 文件,并写入下面的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
    pid_t child_pid;

    child_pid = fork();

    if (child_pid > 0) {
        sleep(600);
    } else if (child_pid == 0) {
        exit(0);
    } else {
        perror("Fork failed");
        return 1;
    }

    return 0;
}

编译程序:

$ gcc zombie.c -o zombie

运行程序:

$ ./zombie

4.2 排查并解决僵尸进程

先用 top 粗略判断系统中是否存在僵尸进程:

演示僵尸进程-1

使用 ps 找到状态为 Z 的进程,例如这里的 PID 为 21313

$ ps aux | grep Z

USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      21313  0.0  0.0      0     0 pts/1    Z+   15:17   0:00 [zombie] <defunct>
root      21319  0.0  0.0 112812   944 pts/0    S+   15:18   0:00 grep --color=auto Z

安装 psmisc 并使用 pstree 查找僵尸进程的父进程,例如 PPID 为 21312

$ yum install -y psmisc
$ pstree -ap

参数说明:

  • -a:显示完整命令信息
  • -p:显示进程 PID

演示僵尸进程-2

最后结束父进程:

$ kill -9 21312

五、小结

学习 Linux 进程时,建议优先掌握三件事:

  • 进程是运行中的程序实例,而程序只是磁盘上的静态文件。
  • 进程有不同分类,前台、后台、守护、父子关系和交互方式都属于常见视角。
  • 僵尸进程和孤儿进程虽然名字相近,但成因与处理方式完全不同,实际排障时一定要区分清楚。