linux 僵尸进程处理
什么是僵尸进程
我们启动一个程序,开始我们的任务,然后等任务结束了,我们就停止这个进程。 进程停止后, 该进程就会从进程表中移除。
但是,有时候有些程序即使执行完了也依然留在进程表中。那么,这些完成了生命周期但却依然留在进程表中的进程,我们称之为 “僵尸进程”。
它们是如何产生的
当你运行一个程序时,它会产生一个父进程以及很多子进程。 所有这些子进程都会消耗内核分配给它们的内存和 CPU 资源。
这些子进程完成执行后会发送一个 Exit 信号然后死掉。这个 Exit 信号需要被父进程所读取。父进程需要随后调用 wait命令
来读取子进程的退出状态,并将子进程从进程表中移除。
若父进程正确第读取了子进程的 Exit 信号,则子进程会从进程表中删掉。
但若父进程未能读取到子进程的 Exit 信号,则这个子进程虽然完成执行处于死亡的状态,但也不会从进程表中删掉。
僵尸进程对系统有害吗
不会。由于僵尸进程并不做任何事情, 不会使用任何资源也不会影响其它进程, 因此存在僵尸进程也没什么坏处。 不过由于进程表中的退出状态以及其它一些进程信息也是存储在内存中的,
因此存在太多僵尸进程有时也会是一些问题,并且由于操作系统所能创建的最大进程数量是有限的(进程号被大量占用)会导致新的进程无法创建。
找出僵尸进程
通过top命令可以看到僵尸进程的数目
在终端并输入下面命令会列出进程表中所有僵尸进程的详细内容。
ps aux |grep Z
如何杀掉僵尸进程
正常情况下我们可以用 SIGKILL
信号来杀死进程,但是僵尸进程已经死了, 你不能杀死已经死掉的东西。 因此需要输入如下命令
kill -s SIGCHLD pid
将这里的 pid 替换成父进程的进程 id,这样父进程就会删除所有以及完成并死掉的子进程了。
不过许多程序写的不是那么完美,无法及时删掉这些子僵尸。 因此确保删除子僵尸的唯一方法就是杀掉它们的父进程。
我们可以模拟一个僵尸进程的产生并找到它
#include#include #include int main(void) { int i = 100; pid_t pid=fork(); if(pid < 0) { perror("fork failed."); exit(1); } if(pid > 0) { printf("This is the parent process. My PID is %d.\n", getpid()); for(; i > 0; i--) { sleep(1); } } else if(pid == 0) { printf("This is the child process. My PID is: %d. My PPID is: %d.\n", getpid(), getppid()); } return 0; }
可以看到产生了一个僵尸进程
可以通过如下命令找出所有僵尸进程的父进程,处理不了可以通过杀死父进程来清理僵尸进程。
ps -eo ppid,stat |grep Z |awk '{print $1}' |sort |uniq
一个正常的进程
下面的 demo 中,父进程通过 wait() 等待子进程结束
#include#include #include #include #include int main(void) { pid_t pid; pid = fork(); if (pid < 0) { perror("fork failed"); exit(1); } if (pid == 0) { int i; for (i = 3; i > 0; i--) { printf("This is the child\n"); sleep(1); } exit(3); } else { int stat_val; wait(&stat_val); if (WIFEXITED(stat_val)) { printf("Child exited with code %d\n", WEXITSTATUS(stat_val)); } } return 0; }