第三章九析带你处理zombie(defunct)进程
目录
10年积累的成都网站设计、做网站经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站制作后付款的网站建设流程,更有剑川免费网站建设让你可以放心的选择与我们合作。
1 前言
2 僵尸进程
2.1 进程简介
2.2 僵尸进程例子
2.3 僵尸进程危害
3 处理僵尸进程
3.1 kill 命令
3.2 kill 父进程
3.3 reboot
3.4 magic sysrq key 方法
1 前言
在 centos7 跑 Docker 和 k8s 时,偶尔会出现 systemctl 失效的情况,现象如下:
Failed to get properties...
查看系统进程,发现僵尸进程(zombie/defunct):
ps -ef | grep defunct
2 僵尸进程
2.1 进程简介
在 linux 中,父进程通过 fork 调用创建子进程。
子进程执行完毕之后,内核会释放该子进程所占用的资源,包括打开的文件,占用的内存等,但仍然会在进程表中保留一个槽位(slot)存放该子进程的文件描述符(比如进程PID、进程退出状态、进程运行时间等),直到父进程发送 wait() 或 waitpid() 调用,内核才会把子进程文件描述符从进程表中彻底清除。如果父进程不调用 wait() 或 waitpid()对子进程进行清理,那子进程将处于僵尸状态。
但是如果父进程先于子进程结束的话,会导致子进程变成僵尸进程吗?答案是不会。因为每当进程结束的时候,系统都会扫描当前所有运行的进程,查找是否有这个结束进程的子进程,如果有,就由 init 进程(或者 systemd 进程)来接管子进程,成为子进程的新父进程,并自动 wait 这个子进程,确保以后该子进程不会变成僵尸进程。
2.2 僵尸进程例子
下面展示一个 c 语言编写的僵尸进程样例,样例中主进程并不会 wait 子进程,生成文件 zombie.c:
#include
#include
#include
int main(void) {
int i = 60;
pid_t pid = fork();
if ( pid < 0 ) {
perror( "fork error." );
exit(1);
}
if ( pid == 0 ) {
printf( "This is the child process. My PID is: %d. My PPID is: %d\n", getpid(), getppid() );
}
if (pid > 0) {
printf( "This is the parent process. My PID is %d.\n", getpid() );
for( ; i > 0; i-- ) {
sleep(1);
}
}
return 0;
}
编译 zombie.c 并执行 zombie:
yum install gcc
gcc zombie.c -o zombie
./ zombie
上图中主进程 PID:11552,子进程 PID:11553。执行如下语句:发现 PID 为 11553 的子进程正好处于僵尸状态(defunct),由程序可知,因为主进程并没有 wait 子进程。
ps aux | grep -i defunct
分析一下 zombie.c,特别注意 fork() 调用,在 pid_t pid = fork() 语句之前,只有一个进程,但是执行到这条语句之后,就变成2个进程了,这2个进程几乎完全相同,将要执行的下一条语句都是 if ( pid < 0 )。
fork() 函数比较特殊,它被调用一次,却能够返回两次结果,它的返回值也根据进程的不同而不同:
1)在父进程中,fork 返回新创建子进程的 PID
2) 在子进程中,fork 返回 0
3)如果出现错误,则 fork 返回负值
2.3 僵尸进程危害
如果父进程没有 wait 子进程,子进程将变成僵尸状态,处于僵尸状态的进程将保留进程号(PID),众所周知,操作系统对进程号是有限制的,如果出现大量僵尸进程占用进程号,系统有可能无法创建新的进程。
3 处理僵尸进程
一般情况下处于僵尸状态的进程很难杀掉,当然你可以试着删除:
3.1 kill 命令
kill -9 PID
3.2 kill 父进程
kill -9 PPID
3.3 reboot
如果采用上面两种方式依然杀不掉,那么只能通过重启了。
reboot
如果重启也不生效,可以需要加选项 -nf
reboot -nf
3.4 magic sysrq key 方法
有时执行 reboot 命令还是无法重启,可以执行 magic sysrq 方法来通过提供给用户的 proc 接口直接向 kernel 发底层命令。
重启命令如下:
echo 1 > /proc/sys/kernel/sysrq
echo b > /proc/sysrq-trigger
强制关机命令:
echo 1 > /proc/sys/kernel/sysrq
echo b > /proc/sysrq-trigger
当前名称:第三章九析带你处理zombie(defunct)进程
链接分享:http://pwwzsj.com/article/gijepj.html