共计 2450 个字符,预计需要花费 7 分钟才能阅读完成。
大安好,我是良许。
本文咱们未来讨论一下什么是僵尸过程,僵尸过程是怎么产生的,如何杀死一个僵尸过程。
Linux 中的过程是什么?
讲到过程,咱们要先理解一下另一个概念:程序
。
程序说白了就是躺在电脑硬盘上的一个文件而已(如同硬盘女神一样),在被 CPU 执行之前,它啥也做不了。
当程序被执行之后,它运行的实例就称为 过程
。一个程序能够对应多个过程。
过程是零碎的工作单元。零碎由多个过程组成,其中有的是操作系统过程(执行零碎代码),其余的是用户过程(执行用户代码)。所有这些过程都会并发执行,例如通过在单 CPU 上采纳多路复用来实现。
你能够应用 ps
命令查看 Linux 零碎中的所有过程。
$ ps -ax
PID TTY STAT TIME COMMAND
1 ? Ss 0:01 /usr/lib/systemd/systemd rhgb --switched-root --sys
2 ? S 0:00 [kthreadd]
3 ? I< 0:00 [rcu_gp]
4 ? I< 0:00 [rcu_par_gp]
当一个过程调用 fork
函数生成另一个过程,原过程就称为父过程,新生成的过程则称为子过程。
Linux 零碎中这样父子过程十分多,咱们能够应用 pstree
命令查看零碎上的过程「谱系」。
$ pstree -psn
systemd(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。它是零碎在疏导过程中执行的第一个过程,PID 1 之后的每个后续过程都是它的后辈。
什么是僵尸过程?
后面提到过,在 Linux 环境中,咱们是通过 fork
函数来创立子过程的。创立结束之后,父子过程独立运行,父过程无奈预知子过程什么时候完结。
通常状况下,子过程退出后,父过程会应用 wait
或 waitpid
函数进行回收子过程的资源,并取得子过程的终止状态。
然而,如果父过程先于子过程完结,则子过程成为孤儿过程。孤儿过程将被 init 过程(过程号为 1)领养,并由 init 过程对孤儿过程实现状态收集工作。
而如果子过程先于父过程退出,同时父过程太忙了,无瑕回收子过程的资源,子过程残留资源(PCB)寄存于内核中,变成僵尸(Zombie)过程,如下图所示:
僵尸过程是怎么产生的?
后面曾经介绍了僵尸过程产生的原理,上面咱们通过代码来模仿僵尸过程的产生。
#include
#include
#include
#include
int main(void)
{
pid_t pid;
pid = fork();
if (pid == 0) {printf("I am child, my parent= %d, going to sleep 3s\n", getppid());
sleep(3);
printf("-------------child die--------------\n");
} else if (pid > 0) {printf("I am parent, pid = %d, myson = %d, going to sleep 5s\n", getpid(), pid);
sleep(5);
system("ps -o pid,ppid,state,tty,command");
} else {perror("fork");
return 1;
}
return 0;
}
在这个程序里,父过程创立子过程之后,就休眠 5 秒钟。而子过程只休眠 3 秒钟就退出,在它退出之后,父过程还未昏迷,因而没人给子过程「收尸」,所以它就变成了僵尸过程。
如何杀死僵尸过程
对于一般过程,咱们能够通过应用 kill
命令来杀死它们。kill
命令它还有几个兄弟,比方 pkill
和 killall
,尽管它们名称里都带 kill
这样杀气腾腾的字眼,但它们实际上是被设计为向一个或多个过程发送信号。
在未指定的状况下,这几个命令默认发送的是 SIGTERM
信号。
一般过程能够被 kill
,但僵尸过程是不行的。为什么?因为僵尸过程自身就曾经「死」过一次了!如果还能够再「死」,那「僵尸」这个名号就没多大意义了。
僵尸过程其实曾经就是退出的过程,因而无奈再利用 kill 命令杀死僵尸过程。僵尸过程的罪魁祸首是父过程没有回收它的资源,那咱们能够想方法它其它过程去回收僵尸过程的资源,这个过程就是 init 过程。
因而,咱们能够间接杀死父过程,init 过程就会很凶恶地把那些僵尸过程领养过去,并正当的回收它们的资源,那些僵尸过程就失去了妥善的解决了。
例如,如果 PID 5878 是一个僵尸过程,它的父过程是 PID 4809,那么要杀死僵尸过程(5878),您能够完结父过程(4809):
$ sudo kill -9 4809 #4809 is the parent, not the zombie
杀死父过程时要十分小心,如果一个过程的父过程就是 PID 1,并且你还杀死了它,那么零碎将间接重启!
这将是一个更可怕的故事!
最初,最近很多小伙伴找我要Linux 学习路线图,于是我依据本人的教训,利用业余时间熬夜肝了一个月,整顿了一份电子书。无论你是面试还是自我晋升,置信都会对你有帮忙!
收费送给大家,只求大家金指给我点个赞!
电子书 | Linux 开发学习路线图
也心愿有小伙伴能退出我,把这份电子书做得更完满!
有播种?心愿老铁们来个三连击,给更多的人看到这篇文章
举荐浏览:
- 干货 | 程序员进阶架构师必备资源免费送
- 书单 | 程序员必读经典书单(高清 PDF 版)