浅谈僵尸进程与孤儿进程

在《unix环境高级编程》中有提到僵尸进程孤儿进程。不少同学对这两个概念会混淆,这篇文章总结一下。

在 unix/linux 系统中,大多情况下,子进程是通过父进程 fork 创建的,注:系统调用 fork,是一个比较有意思系统调用,它调用一次,返回两个值,失败返回 -1,成功时在子进程返回 0,父进程返回所创建子进程的 pid。

子进程创建后,子进程的结束和父进程的运行是一个异步过程,也就是说父进程没办法预测子进程什么时候结束。 当一个子进程完成它的工作终止之后,其父进程需要调用 wait() 或 waitpid() 去获取子进程的终止状态。

孤儿进程

所谓孤儿进程,顾名思义,和现实生活中的孤儿有点类似,当一个进程的父进程结束时,但是它自己还没有结束,那么这个进程将会成为孤儿进程。最后孤儿进程将会被 init 进程(进程号为1)的进程收养,当然在子进程结束时也会由 init 进程完成对它的状态收集工作,因此一般来说,孤儿进程并不会有什么危害。

下面看一个关于孤儿进程的例子:先打印父进程 id,然后创建子进程,让父进程睡眠 5s,让子进程先运行循环打印出其进程 id(pid);随后子进程睡眠 1-3s(此运行过程父进程会结束),目的是让父进程先于子进程结束,让子进程有个孤儿的状态;最后子进程再打印出其进程 id(pid) 以及父进程 id(ppid) ;观察两次打印 其父进程 id(ppid) 的区别。

示例代码:

<?php
// 获取当前进程ID
$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";

$childList = array();

// 创建子进程
$pid = pcntl_fork();
if ( $pid == -1) {
    // 创建失败
    exit("fork progress error!\n");
} else if ($pid == 0) {
    $repeatNum = 10;
    for ( $i = 1; $i <= $repeatNum; $i++) {
        // 子进程执行程序
        $ppid = posix_getppid();
        $pid = posix_getpid();

        echo "PPID:{$ppid} , PID:{$pid} child progress is running! {$i} \n";
        $rand = rand(1,3);
        sleep($rand);
    }
    exit("({$pid})child progress end!\n");
} else {
    // 父进程执行程序
    $childList[$pid] = 1;
}

// 延迟5秒,父进程退出
sleep(5);
echo "({$parentPid})main progress end!\n";

执行过程输出:

孤儿进程演示.png

可以看到,当父进程退出后,子进程被 init 进程收养。子进程执行完毕,init 进程完成对它的状态收集工作。

僵尸进程

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

下面是1个关于僵尸进程的例子,创建子进程,然后让父进程睡眠 90s,让子进程先终止(注意和孤儿进程例子的区别);这里子进程结束后父进程没有调用 wait/waitpid 函数获取其状态,用ps查看进程状态可以看出子进程为僵尸状态。

示例代码:

// 获取当前进程ID
$parentPid = posix_getpid();
echo "parent progress pid:{$parentPid}\n";

$childList = array();

// 创建子进程
$pid = pcntl_fork();
if ( $pid == -1) {
    // 创建失败
    exit("fork progress error!\n");
} else if ($pid == 0) {
    $repeatNum = 10;
    for ( $i = 1; $i <= $repeatNum; $i++) {
        // 子进程执行程序
        $ppid = posix_getppid();
        $pid = posix_getpid();

        echo date('Y-m-d H:i:s') , ' ';
        echo "PPID:{$ppid} , PID:{$pid} child progress is running! {$i} \n";
        $rand = rand(1,3);
        sleep($rand);
    }

    echo date('Y-m-d H:i:s') , ' ';
    exit("({$pid})child progress end!\n");
} else {
    // 父进程执行程序
    $childList[$pid] = 1;
}

// 延迟90秒,父进程退出
sleep(90);

echo date('Y-m-d H:i:s') , ' ';
echo "({$parentPid})main progress end!\n";

执行过程输出:

僵尸进程运行过程.png

僵尸进程状态:

僵尸进程进程状态.png

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

僵尸进程的危害:

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

如何消除僵尸进程:

严格地来说,僵死进程并不是问题的根源,罪魁祸首是产生出大量僵死进程的那个父进程。因此,当我们寻求如何消灭系统中大量的僵死进程时,答案就是把产生大量僵死进程的那个元凶枪毙掉(也就是通过 kill 发送 SIGTERM 或者 SIGKILL 信号)。

枪毙了元凶进程之后,它产生的僵死进程就变成了孤儿进程,这些孤儿进程会被 init 进程接管,init 进程会 wait() 这些孤儿进程,释放它们占用的系统进程表中的资源。这样,这些已经僵死的孤儿进程就能瞑目而去了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容