大安好,我是良许。

本文我们将来讨论一下什么是僵尸进程,僵尸进程是怎么产生的,如何杀死一个僵尸进程。

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 函数来创建子进程的。创建完毕之后,父子进程独立运行,父进程无法预知子进程什么时候结束。

通常情况下,子进程退出后,父进程会使用 waitwaitpid 函数进行回收子进程的资源,并获得子进程的终止状态。

但是,如果父进程先于子进程结束,则子进程成为孤儿进程。孤儿进程将被 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 命令它还有几个兄弟,比如 pkillkillall ,虽然它们名称里都带 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系统僵尸进程详解的更多相关文章

  1. Linux系统守护进程详解ntsysv 可以关掉那些服务

    acpid, haldaemon, messagebus, klogd,network, syslogd  以上几个服务必须开启!其他的分析如下: 1.NetworkManager,NetworkMa ...

  2. LINUX系统VMSTAT命令详解

    linux系统vmstat命令详解 [转自 https://www.cnblogs.com/wensiyang0916/p/6514820.html] vmstat 1    1表示每秒采集一次vms ...

  3. linux 中的进程wait()和waitpid函数,僵尸进程详解,以及利用这两个函数解决进程同步问题

    转载自:http://blog.sina.com.cn/s/blog_7776b9d3010144f9.html 在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / wait ...

  4. Linux系统的信号详解

    一.信号类型 1) SIGHUP       2) SIGINT       3) SIGQUIT     4) SIGILL        5) SIGTRAP 6) SIGABRT      7) ...

  5. Linux系统监控命令详解

    1. top命令 top命令经常用来监控Linux的系统状况,比如cpu.内存的使用,程序员基本都知道这个命令,但比较奇怪的是能用好它的人却很少,例如top监控视图中内存数值的含义就有不少的曲解. 输 ...

  6. MySQL在Linux系统下配置文件详解

    在日常的的开发过程中接触到了SQLServer和MySQL数据库的操作性问题,可能是以前接触的都是SQL Server,才开始接触MySQL,总感觉使用MySQL没有使用SQLserver那么顺手,一 ...

  7. linux系统开机流程详解

    今天,我们主要来谈谈计算机系统的启动流程 1.BIOS启动 BIOS是写入到主板上的一个韧体(韧体就是写入到硬件上的一个软件程序).开机的时候,BIOS是计算机系统会主动执行的第一个程序.BIOS主要 ...

  8. linux系统的负载详解

    系统的平均负载 如何理解平均负载 ​ 单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数. 平均负载多少合理 核心数 平均负载 含义 4 2 有50%的cpu是空闲状态,见 ...

  9. linux系统date命令详解

    Linux时钟分为系统时钟(System Clock)和硬件(Real Time Clock,简称RTC)时钟.系统时钟是指当前Linux Kernel中的时钟,而硬件时钟则是主板上由电池供电的时钟, ...

随机推荐

  1. 实验3:OpenFlow协议分析实践

    作业链接:实验3:OpenFlow协议分析实践 一.实验目的 能够运用 wireshark 对 OpenFlow 协议数据交互过程进行抓包: 能够借助包解析工具,分析与解释 OpenFlow协议的数据 ...

  2. mysql-router-MIC-8.0.26集群部署

    1.具体部署详情请看视频 https://space.bilibili.com/677825194 2.mysql主要配置如下 cat > /etc/my.cnf <<EOF [cl ...

  3. Java初步学习——2021.09.23每日报告,第三周周四

    (1)今天做了什么: (2)明天准备做什么? (3)遇到的问题,如何解决? 学习数组,编写了一个随机选牌的代码.自己最开始一直想只设置一个字符串数组,利用随机数来输出,但那样对字符串赋值会比较麻烦.可 ...

  4. Linux系统安装MySql5.7并通过sql脚本导入数据

    为了下载到的MySQL版本和目标系统相互兼容,在开启之前,最好了解目标系统的相关信息. 查询系统版本: cat /etc/issue 查看系统位数 getconf LONG_BIT 选择MySQL 根 ...

  5. android和IOS自动化定位方法

    元素定位 方法:id定位,name定位(text定位),class_name定位, accessibility_id定位,xpath定位等 (目前1.5版本的已经不支持name定位了),所以APP的定 ...

  6. 2020.3.28-ICPC训练联盟周赛,选用试题:UCF Local Programming Contest 2016

    A.Majestic 10 签到题. #include<iostream> #include<cstdio> #include<cstring> #include& ...

  7. C 可变参数列表 stdarg.h

    内容来自<c和指针>,整理后方便个人理解 stdarg.h 菜鸟教程 - <stdarg.h> 类型 va_list 宏 va_start va_arg va_end #inc ...

  8. Flink sql 之 TopN 与 StreamPhysicalRankRule (源码解析)

    基于flink1.14的源码做解析 公司内有很多业务方都在使用我们Flink sql平台做TopN的计算,今天同事突然问到我,Flink sql 是怎么实现topN的 ? 蒙圈了,这块源码没看过啊 , ...

  9. 【UE4 设计模式】状态模式 State Pattern

    概述 描述 允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类. 其别名为状态对象(Objects for States),状态模式是一种对象行为型模式. 有限状态机(FSMs) ...

  10. django-admin和django-admin.py的区别

    问题 django初学者在使用django-admin创建项目时容易出现无法创建的错误,这是因为网上很多教程用的都是django-admin.py创建的项目,不出意外的话,你输入相同的命令会发现项目没 ...