文章目录
- 1.进程状态
- 1.1 linux内核源码定义
- 1.2 进程状态查看
- 2.僵尸进程
- 3.孤儿进程
- 4.僵尸进程危害
1.进程状态
1.1 linux内核源码定义
cpp/* *The task state array is a strange "bitmap" of *reasons to sleep. Thus "running" is zero, and *you can test for combinations of others with *simple bit tests. */ static const char *const task_state_array[] = { "R (running)", /*0 */ "S (sleeping)", /*1 */ "D (disk sleep)", /*2 */ "T (stopped)", /*4 */ "t (tracing stop)",/*8 */ "X (dead)", /*16 */ "Z (zombie)", /*32 */ };Linux内核定义了一个字符指针数组
task_state_array,用于表示Linux内核中进程的不同状态。每个状态对应一个位掩码值(如0、1、2、4等),可通过位运算检测组合状态。
R (running) - 运行中
状态值:0
进程正在CPU上执行或处于就绪队列等待调度。这是唯一非睡眠状态,其他状态均为阻塞/睡眠的变体。S (sleeping) - 可中断睡眠
状态值:1
进程等待事件完成(如I/O操作),可被信号中断。此时进程不消耗CPU资源,当事件发生后会被移回运行队列。D (disk sleep) - 不可中断睡眠
状态值:2
通常发生在等待磁盘I/O时,进程不可被信号中断。这是保证数据完整性的关键状态,常见于文件系统操作。T (stopped) - 暂停状态
状态值:4
进程被信号(如SIGSTOP)暂停执行,可通过SIGCONT信号恢复。调试器常用此状态控制进程执行流程。t (tracing stop) - 跟踪暂停
状态值:8
调试时由ptrace系统调用触发的特殊暂停状态,与T状态类似但专用于调试器跟踪场景。X (dead) - 死亡状态
状态值:16
进程已完全终止,其资源尚未被父进程回收。该状态是瞬时状态,通常不可被用户空间观察到。Z (zombie) - 僵尸状态
状态值:32
进程已终止但保留进程描述符(存放于PCB中),等待父进程读取退出状态。若父进程未正确处理会导致资源泄漏/内存泄漏
1.2 进程状态查看
bash
ps aux /ps axj
a: 显示一个终端所有进程,包括其他用户的进程
x: 显示没有控制终端的进程,例如后台运行的守护进程
j: 显示进程归属的进程组ID,会话ID,父进程ID,以及与作业控制相关的信息
u: 以用户为中心的格式显示进程信息,提供进程的详细信息,如用户、CPU和内存使用情况

2.僵尸进程(有害)
僵尸进程是指已完成执行(已终止)但仍在进程表中保留条目(未被父进程回收资源)的子进程。其核心特点是进程本身已结束,但系统仍保留其部分信息(如进程ID、退出状态等),等待父进程处理。
cpp#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { pid_t pid = fork(); if (pid == 0) { // 子进程 printf("子进程PID:%d,运行2秒后退出\n", getpid()); sleep(2); exit(0); // 子先死,父没wait } else { // 父进程 printf("父进程PID:%d,休眠10秒(不wait收尸)\n", getpid()); sleep(10); // 父不睡死,子变僵尸 printf("父进程醒了,退出\n"); } return 0; }
- gcc zombie.c -o zombie && ./zombie
- 另开终端查僵尸(状态Z就是僵尸)
ps -aux | grep Z
子进程退出后,父没wait(回收),这8秒内子进程状态是Z(僵尸),占用PID资源
3.孤儿进程(无害)
孤儿进程是指父进程已终止或退出,但子进程仍在运行的进程。由于父进程不再存在,孤儿进程会被系统的
init进程(进程ID为1)接管,由init负责后续的资源回收。
cpp#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { pid_t pid = fork(); if (pid == 0) { // 子进程 printf("子进程PID:%d,父进程PID:%d\n", getpid(), getppid()); sleep(5); // 等父进程先退出 printf("父进程已死,子进程新父PID:%d(变成1)\n", getppid()); } else { // 父进程 printf("父进程PID:%d,马上退出\n", getpid()); exit(0); // 父进程先挂 } return 0; }
- 孤儿进程会持续占用系统资源(如内存、CPU),直到被
init回收。- 无直接危害:与僵尸进程不同,孤儿进程不会导致资源泄漏,最终会被系统清理。
4.僵尸进程危害
- 进程运行结束后,内核不会立刻删除它在进程表(所有PCB的集合****) 里的条目,而是保留进程 ID(PID)、退出状态等信息,等待父进程调用
wait()/waitpid()来 "收尸"。这段时间里,这个只剩 "尸体" 的进程就是僵尸进程。它已经不占用 CPU、内存等运行资源,但会占用一个 PID 和进程表项。2. 核心危害:耗尽 PID 与进程表(内存泄漏)
系统的PID 数量是有限的(比如 Linux 默认最大 PID 是 32768),进程表的容量也有限。
如果父进程一直不调用
wait(),大量僵尸进程会持续占用 PID 和进程表项。当 PID 被耗尽、进程表满了之后,系统无法再创建新的进程------ 比如无法启动新程序、无法打开新终端,甚至系统服务会崩溃。3. 其他间接影响
进程表是内核频繁访问的数据结构,大量僵尸进程会增加内核遍历进程表的开销,轻微降低系统性能。排查问题时,僵尸进程会干扰进程状态的判断,增加运维复杂度。