Linux系统僵尸进程详解

Linux系统僵尸进程详解

大安好,我是良许。

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

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)&#x2500;&#x252C;&#x2500;systemd-journal(952)
        &#x251C;&#x2500;systemd-udevd(963)
        &#x251C;&#x2500;systemd-oomd(1137)
        &#x251C;&#x2500;systemd-resolve(1138)
        &#x251C;&#x2500;systemd-userdbd(1139)&#x2500;&#x252C;&#x2500;systemd-userwor(12707)
        &#x2502;                     &#x251C;&#x2500;systemd-userwor(12714)
        &#x2502;                     &#x2514;&#x2500;systemd-userwor(12715)
        &#x251C;&#x2500;auditd(1140)&#x2500;&#x2500;&#x2500;{auditd}(1141)
        &#x251C;&#x2500;dbus-broker-lau(1164)&#x2500;&#x2500;&#x2500;dbus-broker(1165)
        &#x251C;&#x2500;avahi-daemon(1166)&#x2500;&#x2500;&#x2500;avahi-daemon(1196)
        &#x251C;&#x2500;bluetoothd(1167)

每个进程在系统中都被分配了一个编号。在这所有的进程中,有个非常特殊的进程,它的 ID 号是 1 。它是系统在引导过程中执行的第一个进程,PID 1 之后的每个后续进程都是它的后代。

什么是僵尸进程?

前面提到过,在 Linux 环境中,我们是通过 fork 函数来创建子进程的。创建完毕之后,父子进程独立运行,父进程无法预知子进程什么时候结束。

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

但是,如果父进程先于子进程结束,则子进程成为孤儿进程。孤儿进程将被 init 进程(进程号为1)领养,并由 init 进程对孤儿进程完成状态收集工作。

而如果子进程先于父进程退出,同时父进程太忙了,无瑕回收子进程的资源,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程,如下图所示:

Linux系统僵尸进程详解

僵尸进程是怎么产生的?

前面已经介绍了僵尸进程产生的原理,下面我们通过代码来模拟僵尸进程的产生。

#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 秒钟就退出,在它退出之后,父进程还未苏醒,因此没人给子进程「收尸」,所以它就变成了僵尸进程。

Linux系统僵尸进程详解

如何杀死僵尸进程

对于普通进程,我们可以通过使用 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 ,并且你还杀死了它,那么系统将直接重启!

这将是一个更可怕的故事!

Original: https://www.cnblogs.com/yychuyu/p/15553400.html
Author: 良许Linux
Title: Linux系统僵尸进程详解

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/611766/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • manjaro镜像官方下载

    manjaro国内下载地址,收藏 https://mirrors.tuna.tsinghua.edu.cn/osdn/storage/g/m/ma/manjaro-jp/ http…

    Linux 2023年6月8日
    0512
  • WEB自动化-10-Page Object 模型

    10 Page Object 模型 10.1 概述 在针对一个WEB页面编写自动化测试用例时,需要引用页面中的元素( 数据)才能进行操作( 动作)并显示出页面内容。如果编写的测试用…

    Linux 2023年6月7日
    086
  • 如何在EMACS 设置格式

    如何设置Emacs的各种模式, 这个教程要观摩一下的 http://www.emacswiki.org/emacs/IndentingC#toc1 Original: https:…

    Linux 2023年6月14日
    0110
  • 6.19(junit–>在maven和Spring中的使用)

    写文章要不忘初心,今天也要继续努力~ 白盒测试:是一种测试用例设计方法,在这里盒子指的是被测试的软件,白盒,顾名思义即盒子是可视的,你可以清楚盒子内部的东西以及里面是如何运作的,因…

    Linux 2023年6月7日
    0106
  • urandom和random区别

    linux中提供了 /dev/urandom 和 /dev/random 两个特殊设备来提供随机数。那么这两个文件有什么区别呢?要回答这个问题,先需要了解熵这个概念。 熵linux…

    Linux 2023年6月7日
    085
  • linux inode 详解 / 线上inode爆满解决方案

    linux inode 详解 / 线上inode爆满解决方案 本文大量参考阮一峰大神博客,整理笔记 &#x4E4B;&#x6240;&#x4EE5;&amp…

    Linux 2023年6月7日
    0117
  • 我为儿子开发的第一款Android App,用于九九乘法练习

    用一天时间在macbook上安装好了Android Studio For Mac,注意dl.google.com只支持电信网络下载,家里宽带如果是移动或者联通的,使用AS下载And…

    Linux 2023年6月14日
    0101
  • opencv

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Linux 2023年6月14日
    0116
  • 新一代高性能USB转串口芯片CH342与CH343

    CH342与CH343是沁恒推出的第三代USB转串口产品,内部高度集成,外围精简,均提供VIO电源引脚,串口I/O支持独立供电。 CH342实现USB转两路高速异步串口,支持串口波…

    Linux 2023年6月7日
    0153
  • linux全新机器环境搭建流程梳理

    软件解压后安装基础指令(复制用):./configure && make && make install ./configure –pr…

    Linux 2023年6月6日
    090
  • Java基础系列–05_面向对象

    1、概述:(1)面向过程:将问题一步一步的解决的过程(详细步骤),在C语言中所有的代码都是基于过程化的代码。(2)面向对象:面向对象是基于面向过程的编程思想,所有的事情都交由创建出…

    Linux 2023年6月7日
    0113
  • 如何使用CMake构建c++项目

    1. c++项目构建与CMake简介 在Windows系统上我们通常使用 Visual Studio(VS)来生成我们的c++项目。我们只需在VS相应的层次目录中添加相应的文件即可…

    Linux 2023年5月27日
    0212
  • phpredis中文手册——《redis中文手册》 php版

    将值value关联到key,并将key的生存时间设为seconds(以秒为单位)。 这个命令类似于以下两个命令: O(1) SETRANGE SETRANGE key offset…

    Linux 2023年5月28日
    086
  • Redis深入浅出

    bash;gutter:true; RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前…

    Linux 2023年5月28日
    0111
  • c++仿照go语言的error,函数返回值封装

    c++仿照go语言,程序返回错误时,可以附加错误信息 #ifndef __ERRORMSG_H_ #define __ERRORMSG_H_ #include struct Err…

    Linux 2023年6月14日
    092
  • 什么是守护进程?

    在了解守护进程之前,需要先知道什么是什么是终端?什么是作业?什么是进程组?什么是会话? 在 Linux 中, 每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都…

    Linux 2023年6月8日
    0124
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球