Linux进程状态解析:僵尸与孤儿进程揭秘

文章目录

  • 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;
}
    1. gcc zombie.c -o zombie && ./zombie
    1. 另开终端查僵尸(状态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.僵尸进程危害

  1. 进程运行结束后,内核不会立刻删除它在进程表(所有PCB的集合****) 里的条目,而是保留进程 ID(PID)、退出状态等信息,等待父进程调用 wait()/waitpid() 来 "收尸"。这段时间里,这个只剩 "尸体" 的进程就是僵尸进程。它已经不占用 CPU、内存等运行资源,但会占用一个 PID 和进程表项。

2. 核心危害:耗尽 PID 与进程表(内存泄漏)

系统的PID 数量是有限的(比如 Linux 默认最大 PID 是 32768),进程表的容量也有限。

如果父进程一直不调用 wait(),大量僵尸进程会持续占用 PID 和进程表项。当 PID 被耗尽、进程表满了之后,系统无法再创建新的进程------ 比如无法启动新程序、无法打开新终端,甚至系统服务会崩溃。

3. 其他间接影响

进程表是内核频繁访问的数据结构,大量僵尸进程会增加内核遍历进程表的开销,轻微降低系统性能。排查问题时,僵尸进程会干扰进程状态的判断,增加运维复杂度。

相关推荐
chlk12320 小时前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
舒一笑21 小时前
Ubuntu系统安装CodeX出现问题
linux·后端
改一下配置文件21 小时前
Ubuntu24.04安装NVIDIA驱动完整指南(含Secure Boot解决方案)
linux
深紫色的三北六号1 天前
Linux 服务器磁盘扩容与目录迁移:rsync + bind mount 实现服务无感迁移(无需修改配置)
linux·扩容·服务迁移
SudosuBash1 天前
[CS:APP 3e] 关于对 第 12 章 读/写者的一点思考和题解 (作业 12.19,12.20,12.21)
linux·并发·操作系统(os)
哈基咪怎么可能是AI2 天前
为什么我就想要「线性历史 + Signed Commits」GitHub 却把我当猴耍 🤬🎙️
linux·github
十日十行3 天前
Linux和window共享文件夹
linux
木心月转码ing3 天前
WSL+Cpp开发环境配置
linux
崔小汤呀4 天前
最全的docker安装笔记,包含CentOS和Ubuntu
linux·后端
何中应4 天前
vi编辑器使用
linux·后端·操作系统