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. 其他间接影响

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

相关推荐
c++逐梦人几秒前
进程的优先级与切换
linux·服务器·操作系统
重生之绝世牛码1 分钟前
Linux软件安装 —— Redis集群安装(三主三从)
大数据·linux·运维·数据库·redis·数据库开发·软件安装
网安CILLE4 分钟前
Wireshark 抓包实战演示
linux·网络·python·测试工具·web安全·网络安全·wireshark
是jin奥6 分钟前
Ubuntu 18 安装 nodejs 合适版本
linux·ubuntu·vim
网硕互联的小客服10 分钟前
如何彻底删除CentOS自带的postfix服务释放25端口?
linux·运维·centos
天码-行空15 分钟前
CentOS 误删 /dev 目录救援方案
linux·运维·centos
小码吃趴菜15 分钟前
mysql
linux·运维·服务器
慾玄34 分钟前
第一次渗透
linux
物理与数学1 小时前
Linux 内核 TLB 优化
linux·linux内核
啟明起鸣1 小时前
【Linux 项目管理工具】GDB 调试是现成 C/C++ 项目的 “造影剂”,用来分析项目的架构原理
linux·c语言·c++