linux 下进程与僵尸进程

前言:linux 下进程的运作方式


通俗解释:
    linux 下进程都有父子关系,儿子死了,父亲负责收尸。如果父亲不管,要通知福利院来收尸. 如果父亲连通知都不做,那它那个死掉的儿子就是僵尸。
     如果你只管生,不管死,儿子死的尸横遍野,肯定是你管理不当了。
    linux 用 fork 创建子进程,用wait或waitpid 收尸。用kill 杀死进程(僵尸是杀不掉的)。
    下面看看学术性详细描述:

每个linux 进程在进程表里都有一个进入点(entry),核心进程执行该进程时使用到的一切信息都存储在进入点。
当用 ps 命令察看系统中的进程信息时,看到的就是进程表中的相关数据。
当以fork()系统调用建立一个新的进程后,核心进程就会在进程表中给这个新进程分配一个进入点,然后将相关信息存储在该进入点所对应的进程表内。
这些信息中有一项是其父进程的识别码。

子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程到底什么时候结束。
那么会不会因为父进程太忙来不及 wait 子进程,或者说不知道子进程什么时候结束,而丢失子进程结束时的状态信息呢?
不会。因为linux 提供了一种机制可以保证,只要父进程想知道子进程结束时的状态信息,就可以得到。
这种机制就是:当子进程走完了自己的生命周期后,它会执行exit()系统调用,内核释放该进程所有的资源,
包括打开的文件,占用的内存等。但是仍然为其保留一定的信息,包括进程号(the process ID),退出码(exit code),退出状态(the terminationstatus of the process)
运行时间the amount of CPU time taken by the process等),这些数据会一直保留到系统将它传递给它的父进程为止,直到父进程通过wait / waitpid来取时才释放。
也就是说,当一个进程死亡时,它并不是完全的消失了。进程终止,它不再运行,但是还有一些残留的数据等待父进程收回。
当父进程 fork() 一个子进程后,它必须用 wait() (或者 waitpid())等待子进程退出。正是这个 wait() 动作来让子进程的残留数据消失。
但是如果父进程先于子进程结束了,则子进程会认init 进程为父进程。


一、什么是僵尸进程
僵尸进程是一个早已死亡的进程,但在进程表(processs table)中仍占了一个位置(slot)。
当用ps命令观察进程的执行状态时,看到这些进程的状态栏为defunct。


二、僵尸进程的危害

调度程序无法选中Defunct 进程,所以不能用kill命令删除Defunct 进程
defunct进程占用系统的内存资源,影响系统的性能, 而且如果其数目太多,
将因为没有可用的进程号而导致系统不能产生新的进程。 导致系统瘫痪。
此时的错误为:
fork: retry: Resource temporarily unavailable
查看:
ps -ef  <defunct> 太多

三、僵尸进程的产生

如果子进程死亡时父进程没有 wait(),通常用 ps 可以看到它被显示为“<defunct>”,这样就产生了僵尸进程。它将永远保持这样直到父进程 wait()。
由此可见,defunct进程的出现时间是在子进程终止后,但是父进程尚未读取这些数据之前。

四: 孤儿进程(orphan process)
但是如果该进程的父进程已经先结束了,那么这个进程就成为孤儿进程,那么该进程就不会变成僵尸进程。
因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程,看看有没有哪个进程是刚刚结束的这个进程的子进程,
如果是的话,就由Init进程来接管他,成为他的父进程,从而保证每个进程都会有一个父进程。而Init进程会自动wait其子进程,因此被Init接管的所有进程都不会变成僵尸进程。
就是说,孤儿进程会由init 进程接管。

如果一个程序设计上有缺陷,就可能导致某个进程的父进程一直处于睡眠状态或是陷入死循环,父进程没有wait子进程,也没有终止以使Init接管,
该子进程执行结束后就变成了defunct进程,这个defunct 进程可能会一直留在系统中直到系统重新启动。

四、如何避免僵尸进程
    a、父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起。
    b. 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler。在子进程结束后,父进程会收到该信号,可以在handler中调用wait回收。
    c. 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCLD, SIG_IGN)或signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,
        那么子进程结束后,内核会回收,并不再给父进程发送信号

下面给出一个实例, 放开两处注释中的任一处,都不会产生僵尸进程。 用ps -ef |grep test 观察。
[hjj@hjj ~/test]$ cat test.cpp
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main()
{
//    signal(SIGCLD, SIG_IGN);
    int pid = fork ();
    if (pid == 0)
    {
        printf("child exit now ...");
        _exit (0);
    }
    else
    {
        /*
        int i = 0;
        int status = 0;
        
        while (!waitpid(pid, &status, WNOHANG))
        {
            printf ("father waiting%d\n", ++i);
            sleep (1);
        }
        */
        while (1)
        {
            printf ("father running ...\n");
            sleep (1);
        }
        return 0;
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux 中,僵尸进程和孤儿进程都是指与父进程不再有联系的进程,它们通常是由于进程管理不当或程序错误导致的。 **僵尸进程**是已经完成执行任务,但其父进程还没有来得及处理其退出状态的进程。当进程完成执行后,它的退出状态(也称为退出码或终止状态)会被保存在系统中,直到父进程通过 `wait` 或 `waitpid` 等函数来获取该状态。如果父进程没有处理该状态,那么该进程就会成为僵尸进程,占用系统资源。要清理僵尸进程,可以使用 `kill` 命令向其父进程发送 `SIGCHLD` 信号,或者重新编写程序,使其正确处理子进程的退出状态。 **孤儿进程**是指其父进程已经退出或被终止,但其自身仍在运行的进程。孤儿进程会被 `init` 进程进程号为 `1`)接管,`init` 进程会定期检查系统中是否有孤儿进程,并且将其的父进程设置为 `init` 进程。要避免孤儿进程的产生,可以在父进程退出之前,等待子进程的退出,或者将子进程的父进程设置为 `init` 进程。 可以使用 `ps` 命令来查看系统中的僵尸进程和孤儿进程。使用以下命令可以查看所有僵尸进程: ``` ps aux | grep 'Z' ``` 其中,`aux` 选项用于显示所有进程,`grep 'Z'` 用于查找所有状态为 `Z` 的进程,即僵尸进程。 使用以下命令可以查看所有孤儿进程: ``` ps -ejH ``` 其中,`-e` 选项用于显示所有进程,`-j` 选项用于以层次结构的形式显示进程,`-H` 选项用于显示所有孤儿进程

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值