僵尸进程

1.什么是僵尸进程
一个进程使用fork()创建子进程,如果子进程退出,而父进程并没有调用wait()或waitpid()获取子进程的状态信息,那么子进程的某些信息如进程描述符仍然保存在系统中,这种进程称之为僵尸进程

2.实现僵尸进程
在main函数中,创建子进程,然后让父进程睡眠10s,让子进程先终止(注意和孤儿进程例子的区别),这里子进程结束后父进程没有调用wait()/waitpid()函数获取其状态,用ps查看进程状态可以看出子进程为僵尸状态
3.代码

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
int main()
{
   pid_t pid;
   pid = fork();
   if (pid < 0)
   {
     perror("fork failed");
     exit(1);
   }
  if (pid == 0)
   {
     printf("I am child process.\n");       
     printf("I am eexited.\n");
     exit(0);//先让子进程结束
   }
     printf("I am father process.\n");
     sleep(10);//父进程睡眠10s等待子进程退出,又没调用wait()或waitpid()获取其状态
     子进程成为僵尸进程
     printf("father process is exited.\n");
     return 0;
}

4.运行结果:
这里写图片描述
这里写图片描述
这两个运行结果是程序的运行结果,它们之间会有10s的等待,我们可以用此时间来查看子进程到底有没有成为僵尸进程。

查看僵尸进程的方法:在等待的10s中在另一个终端敲命令ps aux | grep a.out(ps aux | grep name是查看进程的状态的),就可以查看进程的状态
这里写图片描述
5.僵尸进程的危害

僵尸进程会在系统中保留其某些信息如进程描述符、进程id等等。以进程id为例,系统中可用的进程id是有限的,如果由于系统中大量的僵尸进程占用进程id,就会导致因为没有可用的进程id系统不能产生新的进程,这种问题可就大了,这就是僵尸进程来的危害,因此大部分情况下,我们都应当避免僵尸进程的产生。

ps:总而言之,僵尸进程带给我们最大的危害就是内存泄露

6.怎么避免僵尸进程的发生

(1)在父进程中显式的读取子进程的状态

示例1

#include<stdio.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
void handler(int sig)
{
    pid_t ret=0;
    while((ret = waitpid(-1,NULL,WNOHANG))>0)//非阻塞式的等待子进程执行结束
    {
        printf("wait child success!ret is %d\n",ret);
    }
    printf("child quit! pid is %d\n",getpid());
}
int main()
{
    signal(SIGCHLD,handler);
    pid_t pid=fork();
    if(pid==0)
    {
        printf("I am child process. pid is %d\n",getpid());
        sleep(3);
        exit(0);
    }
    while(1)
    {
        printf("father process can something\n");
        sleep(1);
    }
    return 0;
}

运行结果:
这里写图片描述

(2)用signal函数将SIGCHLD信号的处理动作置为SIG_IGN,这样fork出来的进程在终止时会自动清理掉,不会产生僵尸进程,也不会通知父进程

示例2

#include<stdio.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
int main()
{
    signal(SIGCHLD,SIG_IGN);
    pid_t pid=fork();
    if(pid==0)
    {
        printf("I am child process. pid is %d\n",getpid());
        sleep(3);
        exit(0);
    }
    while(1)
    {
        printf("father process can something\n");
        sleep(1);
    }
    return 0;
}

运行结果:这里写图片描述
解析:子进程执行结束,没有通知父进程,此时的进程并没有变为僵尸进程

7.怎么消灭僵尸进程

消灭父进程,那僵尸进程(子进程)就会变为孤儿进程,孤儿进程就会被init进程收养

8.进程的相关知识

任何一个子进程(init进程除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程的数据结构,等待父进程处理,这是每个子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是"Z".如果父进程能及时处理,可能用ps命令就来不及看到子进程的僵尸状态,如果父进程在子进程结束之前退出,则子进程将由init接管,init将会以父进程的身份对僵尸状态的子进程进行处理

Netty 是一个高性能的网络编程框架,广泛用于构建服务器端和客户端应用程序。然而,在某些情况下,使用 Netty 可能会导致僵尸进程(Zombie Process)的出现。僵尸进程是指已经终止但其父进程尚未调用 `wait()` `waitpid()` 来获取其终止状态的进程。这类进程仍然占用系统资源(如进程 ID),如果数量过多,可能会影响系统的稳定性和性能。 ### 僵尸进程的成因 在 Netty 中,僵尸进程的产生通常与以下因素有关: - **子进程的创建**:Netty 本身并不直接创建子进程,但在某些场景下,比如与外部命令交互、使用 `ProcessBuilder` `Runtime.exec()` 启动子进程时,可能会导致僵尸进程的产生。如果父进程没有正确等待子进程的退出状态,子进程就会变成僵尸进程。 - **未处理的信号**:在 Unix/Linux 系统中,当子进程终止时,会向父进程发送 `SIGCHLD` 信号。如果父进程没有正确处理该信号,者忽略了 `SIGCHLD` 信号的处理,子进程的状态将不会被回收,从而导致僵尸进程的产生 [^1]。 ### 僵尸进程的排查 要排查 Netty 应用中是否存在僵尸进程问题,可以通过以下几种方式进行: 1. **使用 `ps` 命令**:通过 `ps -ef | grep defunct` 可以查看当前系统中的僵尸进程僵尸进程的状态通常显示为 `<defunct>`。 2. **检查进程树**:可以使用 `pstree` 命令来查看进程树,确认哪些进程僵尸进程,并追踪它们的父进程。 3. **监控系统资源**:使用 `top` `htop` 等工具监控系统进程状态,观察是否有大量僵尸进程存在。 ### 解决方案 为了防止 Netty 应用中出现僵尸进程,可以采取以下措施: 1. **确保子进程被正确回收**:在创建子进程时,确保父进程调用了 `wait()` `waitpid()` 来回收子进程的状态。如果使用 Java 的 `ProcessBuilder` `Runtime.exec()` 创建子进程,可以通过调用 `process.waitFor()` 来等待子进程结束 [^1]。 ```java Process process = Runtime.getRuntime().exec("some command"); int exitCode = process.waitFor(); ``` 2. **忽略 `SIGCHLD` 信号**:在某些情况下,可以考虑忽略 `SIGCHLD` 信号,这样系统会自动回收子进程的状态,避免僵尸进程的产生。可以通过 `Signal` 类来忽略信号 [^1]。 ```java Signal.handle(new Signal("CHLD"), signal -> {}); ``` 3. **使用守护线程**:如果子进程是由某个线程启动的,可以将该线程设置为守护线程,这样即使子进程没有被正确回收,也不会导致僵尸进程的长期存在。 4. **使用第三方库**:考虑使用更高级别的库来管理子进程,例如 Apache Commons Exec,它提供了更强大的功能来处理子进程的生命周期 [^1]。 5. **定期清理僵尸进程**:在某些情况下,可以通过编写脚本使用工具定期清理僵尸进程。例如,使用 `kill -9 <pid>` 来强制终止僵尸进程,但这并不是推荐的做法,因为这可能会导致资源泄漏。 ### 总结 虽然 Netty 本身不会直接导致僵尸进程的产生,但在与外部命令交互创建子进程时,如果不注意进程的生命周期管理,就可能出现僵尸进程问题。通过合理的设计和管理,可以有效避免此类问题的发生,确保系统的稳定性和性能。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值