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 java 僵尸进程_Linux 系统中僵尸进程相关推荐

  1. linux mysql 僵尸进程_Linux 系统中僵尸进程

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

  2. linux的mysql占用cpu过高_linux 系统中Mysql 进程占用cpu过高的解决

    mysql进程CPU使用率过高,开始报警了. 为了快速解决问题直接重启mysql服务后,再查sysql进程CPU使用率依旧高居不下.故障还没有解决,继续寻找原因. 3.登陆mysql数据库,执行sho ...

  3. linux ftp下载文件_Linux系统中10个使用Wget命令下载文件示例

    wget 是一个从网络上自动下载文件的命令行工具,支持通过 HTTP.HTTPS.FTP 三个最常见的 TCP/IP协议 下载,并可以使用 HTTP 代理.它是一个非交互式工具,非常适合通过脚本或者在 ...

  4. linux java运行环境_linux(centos)中java运行环境_jdk安装与配置 | OPS技术联盟

    系统版本 [root@iZwz95n2hxcdh4x6vicjmgZ ~]# cat /etc/redhat-release CentOS Linux release 7.8.2003 (Core) ...

  5. linux查看mysql版本_Linux系统中查看MySQL版本的五种方法

    1.在Linux终端窗口中,输入mysql -V查看MySQL版本信息[sky@qin ~]# mysql -V mysql Ver 14.14 Distrib 5.1.29-rc, for pc-l ...

  6. linux mutt安装配置_Linux系统中安装配置Mutt来作为Gmail客户端

    mutt是一个Linux终端下的著名的邮件客户端,如你所愿,mutt就是一个邮件客户端.没有其他浮华的功能,它可以帮助你提升效率,至于帮助你装X只能算是mutt的特殊加成. 由于mutt是一个有着un ...

  7. linux mysql 僵尸进程_linux shell中清理僵尸进程

    今天登录到服务器上时,系统打印有6 zombie processes存在,于是用kill -9去清理掉这些僵尸进程,命令执行完后没有错误,可是再次查找时,发现僵尸进程仍然存在,不知道怎么清理了,上网找 ...

  8. linux里面有mysql的僵尸进程_linux 如何清理僵尸进程

    定义 In UNIX System terminology, a process that has terminated,but whose parent has not yet waited for ...

  9. Linux系统中的进程管理

    Linux系统中的进程管理 了解进程 进程是已启动的可执行程序的运行实例,进程有以下组成部分: • 已分配内存的地址空间: • 安全属性,包括所有权凭据和特权: • 程序代码的一个或多个执行线程: • ...

最新文章

  1. Consul + Nginx实现自动扩容平台
  2. 2 172.02 php,kafka安装、相关命令以及PHP使用
  3. Linux ftp 命令
  4. 单元测试JUnit 4 (一)——keeps the bar green to keeps the code clean
  5. python3 数组转字符串_Q:与python3交互中字符串转gbk的问题
  6. 3.11-3.14 Hive 企业使用优化2
  7. python和matlab矩阵运算效率_如何写出比 MATLAB 更快的矩阵运算程序?
  8. java程序员和java架构师有什么区别呢?
  9. 华硕k5555l拆解图解_华硕k50id的拆机过程详解【图文教程】
  10. Python 地图行政区边界方案
  11. 【转载】学习可能用到的英语单词
  12. python最优投资组合_CVXOPT投资组合优化
  13. 4个好用的WebShell网站后门查杀工具 在线木马查杀
  14. 第十三届蓝桥杯大赛软件赛省赛(Java 大学C组)
  15. 超越源域的攻击:面向黑盒域制作对抗样本
  16. linux ln -sv命令,linux ln 命令详解
  17. 由“西游记”的唐僧扫塔想到的
  18. c语言将数据写入文件后乱码_C语言 文件写入输出。文件载入后输出是乱码,纠结啊!...
  19. 华为S5700 S2700交换机 配置
  20. 赴美IPO后,美菜网还能在卖菜行业保持“低调”吗?

热门文章

  1. s:hidden name=id value=id/s:hidden
  2. Python 利用4行代码实现图片灰度化
  3. 人家好害羞啦主题主题下载
  4. 3.4 《数据库系统概论》之数据查询---SELECT(单表查询、连接查询、嵌套查询、集合查询、多表查询)
  5. python中row是什么意思_Python中的2D列表(row total/grand total)
  6. PHP curl 执行结果老是301 Moved Permanently
  7. 阴阳师服务器维护3月14,阴阳师手游抢先体验服3月14日维护更新公告
  8. 找参考图的同志们看过来,分享几个建模参考网站给你们。再不用愁啦
  9. 使用SSH链接Linux报错问题
  10. jersey的使用总结