大家好大安,我是良旭。在本文中,我们将讨论什么是僵尸进程,僵尸进程是如何产生的,以及如何杀死僵尸进程。Linux中的进程是什么?说到流程,首先要了解另一个概念:程序。说白了,程序就是一个躺在电脑硬盘上的文件(就像硬盘女神一样),在被CPU执行之前,它什么也做不了。当程序执行时,它运行的实例称为进程。一个程序可以对应多个进程。进程是系统的工作单元。系统由多个进程组成,其中一些是操作系统进程(执行系统代码),另一些是用户进程(执行用户代码)。所有这些进程都是并发执行的,例如通过在单个CPU上使用多路复用。您可以使用ps命令查看Linux系统中的所有进程。$ps-axPIDTTYSTATTIMECOMMAND1?Ss0:01/usr/lib/systemd/systemdrhgb--switched-root--sys2?S0:00[kthreadd]3?I<0:00[rcu_gp]4?I<0:00[rcu_par_gp]]当一个进程调用fork函数生成另一个进程时,原进程称为父进程,新生成的进程称为子进程。Linux系统中有这么多这样的父子进程,我们可以使用pstree命令查看系统上的进程“谱系”。$pstree-psnsystemd(1)─┬─systemd-journal(952)├─systemd-udevd(963)├─systemd-oomd(1137)├─systemd-resolve(1138)├─systemd-userdbd(1139)─┬─systemd-userwor(12707)│├─systemd-userwor(12714)│└─systemd-userwor(12715)├─auditd(1140)───{auditd}(1141)├─dbus-broker-lau(1164)────dbus-broker(1165)├─avahi-daemon(1166)────avahi-daemon(1196)├─bluetoothd(1167)每个进程在系统中都分配了一个编号。在所有这些进程中,有一个非常特殊的进程,它的ID号是1。它是系统在引导期间执行的第一个进程,PID1之后的每个后续进程都是它的后代。什么是僵尸进程?前面提到,在Linux环境下,我们使用fork函数来创建子进程。创建完成后,父子进程独立运行,父进程无法预测子进程何时结束。通常,子进程退出后,父进程会使用wait或waitpid函数回收子进程的资源,获取子进程的终止状态。但是,如果父进程在子进程之前结束,则子进程成为孤儿进程。孤儿进程会被init进程(进程号1)收养,init进程会完成对孤儿进程的状态收集工作。而如果子进程先于父进程退出,同时父进程太忙,则完美回收子进程的资源,将子进程的剩余资源(PCB)存放在内核中,成为僵尸进程,如下图所示:Zombie进程是如何产生的?前面已经介绍了僵尸进程生成的原理。接下来,我们将通过代码模拟僵尸进程的产生。#include#include#include#includeintmain(void){pid_tpid;pid=fork();if(pid==0){printf("Iamchild,myparent=%d,goingtosleep3s\n",getppid());sleep(3);printf("------------childdie------------\n");}elseif(pid>0){printf("Iamparent,pid=%d,myson=%d,goingtosleep5s\n",getpid(),pid);sleep(5);system("ps-opid,ppid,state,tty,command");}else{perror("fork");return1;}return0;}在这个程序中,父进程创建子进程后,休眠5秒。子进程在退出前只休眠3秒。它退出后,父进程还没有被唤醒,所以没有人“收”子进程,于是就变成了僵尸进程。如何杀死僵尸进程对于正常进程,我们可以使用kill命令来杀死它们。kill命令有几个兄弟,比如pkill和killall。虽然它们的名字中都有kill这样的杀气腾腾的字眼,但它们实际上是为了向一个或多个进程发送信号而设??计的。如果未指定,这些命令默认发送SIGTERM信号。可以杀死普通进程,但僵尸进程不能。为什么?因为僵尸进程本身已经“死”过一次了!如果它能再“死”一次,那“丧尸”这个名字就没有多大意义了。僵尸进程实际上是一个退出的进程,所以不能使用kill命令杀死僵尸进程。僵尸进程的罪魁祸首是父进程没有回收它的资源,那么我们可以想办法让其他进程回收僵尸进程的资源,这个进程就是init进程。因此,我们可以直接杀掉父进程,init进程会好心收养那些僵尸进程,合理回收它们的资源,那些僵尸进程就会得到妥善处理。例如,如果PID5878是一个僵尸进程,它的父进程是PID4809,那么要杀死僵尸进程(5878),可以杀死父进程(4809):$sudokill-94809#4809istheparent,notthezombiekilltheparentprocess非常小心,如果一个进程的父进程是PID1,当你杀死它时,系统只会重启!那将是一个更可怕的故事!
