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)

大家都在看

  • Sql Server Proc 先看看简单吧

    –以上是语句库 –先看看不带参数的吧 他跟方法一样 可以带参数也可以不带参数(当然我没用过几次不带参数的) –获取一个表吧这种都感觉像视图了 &…

    Linux 2023年6月7日
    0133
  • CentOS7安装部署Zabbix监控服务

    Zabbix Server通过Agent传来的数据写入数据库(MySQL),最终通过PHP+Apache在Web界面进行前端展示所以在启动Zabbix之前需要搭建LAMP环境 1、…

    Linux 2023年5月27日
    0119
  • Linux 配置Maven(避免踩坑篇)

    前言:请各大网友尊重本人原创知识分享,谨记本人博客: 南国以南i 二、下载好的maven安装包放在磁盘的 /usr/local/ 目录下,如下图: 三、解压该压缩文件 tar -z…

    Linux 2023年5月27日
    0101
  • Jstack排查线上CPU100%

    Jstack排查线上CPU100% 介绍 jstack是JVM自带的Java堆栈跟踪工具,用于生成java虚拟机当前时刻的线程快照,来帮助定位线程出现长时间停顿的原因,例如死锁、死…

    Linux 2023年6月6日
    0110
  • 自动化集成:Pipeline整合Docker+K8S

    前言:该系列文章,围绕持续集成:Jenkins+Docker+K8S相关组件,实现自动化管理源码编译、打包、镜像构建、部署等操作; 本篇文章主要描述流水线集成K8S用法。 一、背景…

    Linux 2023年5月27日
    0173
  • 利用 C# 给 Windows 资源管理器注册右键菜单(Windows Shell)(一):入门

    前言 关于 SharpShell SharpShell makes it easy to create Windows Shell Extensions using the .NE…

    Linux 2023年5月28日
    091
  • 用动态端口,增强winrm,open sshd的,服务器安全

    前言 我开发了一套开源,免费,跨平台的devops脚本批量运维工具。【kaiiit家的饭店】是软件的正式名字。【卡死你3000】是第一版开发代号。 想要增强win被控机密码安全。可…

    Linux 2023年6月14日
    085
  • 不要让“Clean Code”更难维护,请使用“Rule of Three”

    当人们试图将”代码整洁之道(Clean Code)”的原则应用于现有的代码库时,我经常会问这个问题。 我认为这是合情合理的。 当我们开始重构遗留代码时,通常…

    Linux 2023年6月8日
    094
  • Laxcus远程终端

    Laxcus集群操作系统的远程终端越来越象Linux的VIM了,除了界面风格之外,在用户使用的命令上也在向VIM靠近,原因嘛也不难理解,毕竟Laxcus是一个分布式的操作系统,处理…

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

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

    Linux 2023年6月7日
    086
  • 离职,问题就解决了吗?

    刚入职场的那几年,我经常对工作有各种抱怨。回想起来,有两次冲动的不必要的离职,或者说应该干得更久一点。一旦有了离职的想法,整个人每天都纠结是去还是留,这种纠结成倍的放大焦虑,让自己…

    Linux 2023年6月6日
    0110
  • Redis深入浅出

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

    Linux 2023年5月28日
    0111
  • postgres 错误duplicate key value violates unique constraint 解决方案

    把当前最大的id做为当前的id自增起始数运行下面的SQL就行了 SELECT setval(‘tablename_id_seq’, (SELECT MAX(id) FROM tab…

    Linux 2023年6月14日
    0114
  • JavaScript快速入门-06-函数

    6 函数 6.1 函数定义 函数可以封装语句,然后在任何地方、任何时间执行。JavaScript中的函数使用 function关键字声明,主要由 函数名、 函数参数和 函数体组成。…

    Linux 2023年6月7日
    0110
  • Failed to configure a DataSource ‘url’ attribute问题解决

    才写了一行代码又报错了.. *************************** APPLICATION FAILED TO START ********************…

    Linux 2023年6月13日
    085
  • 教你搞懂Jenkins安装部署!

    前言:请各大网友尊重本人原创知识分享,谨记本人博客: 南国以南i Jenkins介绍 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作…

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