今天在维护服务器的时候,发现有5个nova-novncproxy的僵尸进程。

之前对于僵尸进程的了解并不深,赶紧找了篇相关文章来学习一下,该如何处理。

定义

In UNIX System terminology, a process that has terminated,but whose parent has not yet waited for it, is called a zombie.

在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他, 那么他将变成一个僵尸进程.  在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用 waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程。

如何查看linux系统上的僵尸进程,如何统计有多少僵尸进程?

#ps -ef | grep defunct

或者查找状态为Z的进程,Z就是代表zombie process,僵尸进程的意思。

另外使用top命令查看时有一栏为S,如果状态为Z说明它就是僵尸进程。

Tasks:  95 total,   1 running,  94 sleeping,   0 stopped,   0 zombie

top命令中也统计了僵尸进程。或者使用下面的命令:

ps -ef | grep defunct | grep -v grep | wc -l

如何杀死僵尸进程呢?

一般僵尸进程很难直接kill掉,不过您可以kill僵尸爸爸。父进程死后,僵尸进程成为”孤儿进程”,过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。

ps -e -o ppid,stat | grep Z | cut -d” ” -f2 | xargs kill -9

kill -HUP `ps -A -ostat,ppid | grep -e ’^[Zz]‘ | awk ’{print $2}’`

当然您可以自己编写更好的shell脚本,欢迎与大家分享。

我将nova-novncproxy stop后再start,僵尸进程即消失,问题解决。

另外子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。就是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,而此时,尽管对它的默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。

如何避免僵尸进程呢?

处理SIGCHLD信号并不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下 可以简单地将 SIGCHLD信号的操作设为SIG_IGN。signal(SIGCHLD,SIG_IGN);这样,内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同,BSD4下必须显式等待子进程结束才能释放僵尸进程

或者

用两次fork(),而且使紧跟的子进程直接退出,是的孙子进程成为孤儿进程,从而init进程将负责清除这个孤儿进程。

Linux 系统中僵尸进程和现实中僵尸(虽然我也没见过)类似,虽然已经死了,但是由于没人给它们收尸,还能四处走动。僵尸进程指的是那些虽然已经终止的进程,但仍然保留一些信息,等待其父进程为其收尸。配图源自 Flickr 

僵尸进程如何产生的?

如果一个进程在其终止的时候,自己就回收所有分配给它的资源,系统就不会产生所谓的僵尸进程了。那么我们说一个进程终止之后,还保留哪些信息?为什么终止之后还需要保留这些信息呢?

一个进程终止的方法很多,进程终止后有些信息对于父进程和内核还是很有用的,例如进程的ID号、进程的退出状态、进程运行的CPU时间等。因此进程在终止时,回收所有内核分配给它的内存、关闭它打开的所有文件等等,但是还会保留以上极少的信息,以供父进程使用。父进程可以使用 wait/waitpid 等系统调用来为子进程收拾,做一些收尾工作。

因此,一个僵尸进程产生的过程是:父进程调用fork创建子进程后,子进程运行直至其终止,它立即从内存中移除,但进程描述符仍然保留在内存中(进程描述符占有极少的内存空间)。子进程的状态变成EXIT_ZOMBIE,并且向父进程发送SIGCHLD 信号,父进程此时应该调用 wait() 系统调用来获取子进程的退出状态以及其它的信息。在 wait 调用之后,僵尸进程就完全从内存中移除。因此一个僵尸存在于其终止到父进程调用 wait 等函数这个时间的间隙,一般很快就消失,但如果编程不合理,父进程从不调用 wait 等系统调用来收集僵尸进程,那么这些进程会一直存在内存中。

在 Linux 下,我们可以使用 ps 等命令查看系统中僵尸进程,僵尸进程的状态标记为‘Z’:

产生一个僵尸进程

根据上面的描述,我们很容易去写一个程序来产生僵尸进程,如下代码:#include #include int main(){

//fork a child process

pid_t pid = fork();

if (pid > 0)   //parent process

{

printf("in parent process, sleep for one miniute...zZ...\n");

sleep(60);

printf("after sleeping, and exit!\n");

}

else if (pid == 0)

{

//child process exit, and to be a zombie process

printf("in child process, and exit!\n");

exit(0);

}

return 0;}

父进程并没有写 wait 等系统调用函数,因此在子进程退出之后变成僵尸进程,父进程并没有为其去收尸。我们使用下面命令编译运行该进程,然后查看系统中进程状态:guohailin@guohailin:~/Documents$ gcc zombie.c -o zombie

guohailin@guohailin:~/Documents$ ./zombie

in parent process, sleep for one miniute...zZ...

in child process, and exit!

# 打开另一个终端:

guohailin@guohailin:~$ ps aux | grep -w 'Z'

1000      2211  1.2  0.0      0     0 ?        Z    13:24   6:53 [chromium-browse]

1000      4400  0.0  0.0      0     0 ?        Z    10月16   0:00 [fcitx]

1000     10871  0.0  0.0      0     0 pts/4    Z+   22:32   0:00 [zombie]

从上面可以看出,系统中多了一个僵尸进程。但如果等父进程睡眠醒来退出之后,我们再次查看系统进程信息,发现刚才的僵尸进程不见了。guohailin@guohailin:~/Documents$ ./zombie

in parent process, sleep for one miniute...zZ...

in child process, and exit!

after sleeping, and exit!

guohailin@guohailin:~/Documents$ ps aux | grep -w 'Z'

1000      2211  1.2  0.0      0     0 ?        Z    13:24   6:53 [chromium-browse]

1000      4400  0.0  0.0      0     0 ?        Z    10月16   0:00 [fcitx]

这是为什么呢?父进程到死都也没有为其子进程收尸呀,怎么父进程退出之后,那个僵尸进程就消失了呢?难道父进程在退出时会为子进程收拾吗?其实不然....真正的原因是:父进程死掉之后,其所有子进程过继给 init 进程,init 进程成为该僵尸进程的新进程,init 进程会周期性地去调用 wait 系统调用来清除它的僵尸孩子。因此,你会发现上面例子中父进程死掉之后,僵尸进程也跟着消失,其实是 init 进程为其收尸的!

怎样避免僵尸进程的产生

不能使用 kill 后接 SIGKILL 信号这样的命令像杀死普通进程一样杀死僵尸进程,因为僵尸进程是已经死掉的进程,它不能再接收任何信号。事实上,如果系统中僵尸进程并不多的话,我们也无需去消除它们,少数的僵尸进程并不会对系统的性能有什么影响。

那么在编程时,如果能避免系统中大量产生僵尸进程呢?根据上面描述的,子进程在终止时会向父进程发 SIGCHLD 信号,Linux 默认是忽略该信号的,我们可以显示安装该信号,在信号处理函数中调用 wait 等函数来为其收尸,这样就能避免僵尸进程长期存在于系统中了。示例代码如下:#include #include #include #include #include sig_atomic_t child_exit_status;void clean_up_child_process(int signal_num){

/* clean up child process */

int status;

wait (&status);

/* store its exit status in a global variable */

child_exit_status = status;}int main(){

/* handle SIGCHLD by calling clean_up_child_process  */

struct sigaction sigchild_action;

memset(&sigchild_action, 0, sizeof(sigchild_action));

sigchild_action.sa_handler = &clean_up_child_process;

sigaction(SIGCHLD, &sigchild_action, NULL);

/* fork a child, and let the child process dies before parent */

pid_t c_pid;

c_pid = fork();

if (c_pid > 0)

{

printf("in parent process, and sleep for on mininute...zZ...\n");

sleep(60);

}

else if(c_pid == 0)

{

printf("in child process, and exit now\n");

exit(0);

}

else

{

printf("fork failed!\n");

}

return 0;}

参考资料

linux 进程 清理,linux 如何清理僵尸进程相关推荐

  1. Linux | 进程概念、进程状态(僵尸进程、孤儿进程、守护进程)、进程地址空间

    文章目录 进程和程序 操作系统如何控制和调度程序 进程控制块–PCB 子进程 进程状态 僵尸进程 孤儿进程 守护进程(精灵进程) 进程地址空间 引言 页表 进程和程序 程序: 一系列有序的指令集合(就 ...

  2. python僵尸进程和孤儿进程_进程3.0——进程状态与僵尸进程、孤儿进程

    进程3.0--进程状态与僵尸进程.孤儿进程 进程状态 一个进程的生命周期可以划分为一组状态,这些状态刻画了整个进程.进程状态即体现一个进程的生命状态 一般来说,进程有五种状态:创建状态:进程在创建时需 ...

  3. php apache 多进程,php多进程 防止出现僵尸进程 如何 使 apache 成为 僵尸进程

    php pcntl 僵尸进程怎么产生的一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它的作用是使进程退 ...

  4. Linux进程实践(4) --wait避免僵尸进程

    Wait的背景 当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止) 子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程 ...

  5. Linux 进程(一) 进程概念和进程状态(僵尸进程、孤儿进程、守护进程)

    进程的概念 进程状态 僵尸进程.孤儿进程.守护进程 进程的概念 程序:一系列有序的指令集合(就是我们写的代码) 进程:进程就是程序的一次执行,是系统进行资源分配和调度的独立单位. 程序是一个没有生命的 ...

  6. linux php 进程进阶(三) 僵尸进程

    僵尸进程 基本概念 我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程.子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束 ...

  7. linux僵尸进程杀不掉,杀死僵尸进程,你需要这些神奇高效的 Linux 命令

    原标题:杀死僵尸进程,你需要这些神奇高效的 Linux 命令 Linux高手,其实都是玩儿命令行很熟练的人. 命令行的学习捷径 Linux命令有许多强大的功能:从简单的磁盘操作.文件存取,到进行复杂的 ...

  8. Linux信号:SIGCHLD信号和僵尸进程

    1. SIGCHLD信号产生条件: (1)子进程终止: (2)子进程收到SIGSTOP信号被暂停: (3)子进程处于暂停状态,收到SIGCONT信号被唤醒. 2. 捕捉SIGCHLD,避免僵尸进程: ...

  9. 进程(Process)基础知识(孤儿,僵尸进程)

    目录 冯诺依曼体系: 操作系统: 进程概念: 进程状态 进程创建 僵尸进程 孤儿进程 环境变量(path) 程序地址空间 页面置换算法 缺页中断 冯诺依曼体系: 计算机硬件体系结构-五大硬件单元 输入 ...

  10. 关于进程(PCB | 父进程 | 子进程 | fork深层探讨 |僵尸进程与孤儿进程)

    文章目录 一.进程与PCB 1. 进程的概念: 2. 什么是PCB task_struct task_ struct内容分类 4. 查看进程 5. 进程概念的加深 二.父进程与子进程 1. 通过系统调 ...

最新文章

  1. Ubuntu 下Ape转Mp3[88250原创]
  2. Kingbase金仓更改表空间
  3. 新闻发布项目——业务逻辑层(commentService)
  4. 桥接模式coding
  5. CPU缓存一致性协议MESI - 笔记
  6. CAMoE——屠榜 video retrieval challenge
  7. do_something方法解析
  8. python删除csv某一行_用Python一步从csv中删除特定的行和列
  9. 20172330 2017-2018-1 《Java程序设计》第八周学习总结
  10. 算法学习之路|反转链表
  11. RTSP的音频视频要各SETUP一次
  12. sun的EJB开发文档
  13. iredmail邮箱使用
  14. 布同:如何循序渐进学习Python语言
  15. html图片右边加竖线,插入Html竖线代码
  16. 三阶魔方层先还原方法图解2
  17. screentogif能录制声音吗_如何用Screen to Gif快速录制动图
  18. jtag和swd区别,该用哪个?
  19. 紫丁香终于没有坚持到第11年
  20. 车载调频广播电台移动发射系统应用

热门文章

  1. 计算机软件产品类退税,软件产品增值税退税政策详解.doc
  2. 【广东大学生网络攻防大赛-WriteUp(非官方)】Reverse | pyre
  3. ArGIS Engine专题(8)之利用GP监督分类最大似然法实现根据矢量样本和影像提取植被类型
  4. excel查看编码格式_Excel表格中格式转换的这些套路,你都get了吗?
  5. 迅捷PDF编辑器如何编辑PDF文字图文教程
  6. ❤️工作半年前端的一些思考 | 共勉
  7. 知识驱动的主动式开放域对话系统 by 车万翔 2020/4/11
  8. dog log 算子_图像特征之LoG算子与DoG算子
  9. 贝叶斯决策论及朴素贝叶斯分类器
  10. clonezilla使用_如何使用Clonezilla备份和恢复已死或即将死去的系统磁盘