僵尸进程
说到UNIX编程,有一个问题不得不说,那就是僵尸进程问题。如果你在简历上写了熟悉UNIX、Linux编程,恐怕面试官十有八九会问到僵尸进程问题。对于一个长期运行的服务器来说,僵尸是非常可怕的,编程上的疏忽导致僵尸进程的产生,随着时间的推移僵尸进程会越来越多,最终对服务器性能造成明显的影响。因此了解僵尸进程并且防止僵尸进程的产生就显得非常重要了。 什么是僵尸进程?当一个进程结束之后,系统仍会保留这个进程的ID以及结束状态等信息,如果这个信息没有被清理掉的话,我们就可以说这个进程变成了僵尸进程。不过这些内容仅仅是僵尸进程的一个概念性的问题,并不是实质问题,我们应该知道为什么会产生僵尸进程,也就是系统为什么要保留一个进程的结束信息。一个显而易见的问题就是一个进程可能在任意的时间点结束,我们无法确定,同时一个进程的父进程有理由知道自己创建的子进程以什么样的状态退出。更加重要的就是父进程无法预计子进程会在什么时刻结束,因此在子进程结束的时候,父进程很有可能在忙着做其它事情并不希望一直等待到子进程的结束。因此保留进程的退出信息是有必要的。 一般来说处理方法是让父进程捕获SIGCHLD信号(选择忽略该信号的行为是没有保证的),之后在信号处理函数中调用wait或者是waitpid函数。这样的做法在有些时候是有效的,比如说进程只有一个子进程的情况下(父进程不希望一直等待子进程结束)。当然了,如果此时父进程可以等待到子进程结束的话,完全可以在fork之后就直接调用wait或者waitpid函数。 《UNIX网络编程》中提到了一种比较难以想到,但又是一种比较容易发生的情况,就是在并发服务器上,几乎相同的时间点有多个子进程结束。不幸的是此时父进程仅仅接收到一个SIGCHLD信号,关于这个问题《UNIX环境高级编程》中第10章有详细的说明,这里就不再赘述了。那么如果我们在信号处理函数调用一次wait或waitpid函数,那么就存在这样一种可能,其它几近同时结束的进程状态并没有被wait或waitpid函数获取,这个时候僵尸仍然是存在的,在最坏的情况下会有大量结束的子进程需要等待父进程来处理,如果父进程是一个长期运行的进程,那么系统中就会充满了僵尸进程。就这个问题《UNIX网络编程》中给出了一种简单有效的方法,在信号处理程序中也非阻塞的方式循环调用waitpid函数等待任何的子进程结束,直到waitpid函数返回一个错误(此时可能要判断errno的值)。这就有效的解决了并发服务器上出现僵尸进程问题,而且不会出现在多个子进程同时结束时部分子进程的结束状态没有父进程获取的问题。我们要补充的是,一般等待一个进程结束往往使用的是waitpid函数和wait4函数,而不是wait和wait3函数。 对于僵尸进程而言,我们需要知道如何查看是否有僵尸进程存在。我个人是非常喜欢使用top命令来查询系统中是否存在僵尸进程,当然还有别的办法可以查看僵尸进程,《鸟哥的Linux私房菜》对这些Linux基本命令有较详细的说明,这里就不再赘述了。这里有一件有趣的事情,如果你知道一个进程早该结束了,那么通过pstree命令也能看出来一些端倪,一些早就结束的进程在pstree上居然还能看到,那么说明一个问题,这些进程一定变成了僵尸(这个方法比较非主流,但是确实说明了一些问题)。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。