如何找到并终止 Linux 系统中的僵尸进程

Python028

如何找到并终止 Linux 系统中的僵尸进程,第1张

在了解僵尸进程之前,让我们来复习一下什么是 Linux 进程。

简而言之, 进程 [1] 是一个程序的运行实例。它可能运行在前端(比如有交互的进程),也可能运行在后端(比如无交互或自动运行的进程)。它可能是一个父进程(运行期间创建了其他进程),也可能是一个子进程(由其他进程所创建)。

在 Linux 系统中,除 PID 为 0 的第一个 init 进程(或 systemd )外,其余进程都有父进程。进程也可以拥有自己的子进程。

不相信?可以试试在终端中使用 pstree 命令查看进程的树型结构,你能看到系统各个进程的“家族树”。

子进程死亡后,它的父进程会接收到通知去执行一些清理操作,如释放内存之类。然而,若父进程并未察觉到子进程死亡,子进程就会进入到“<ruby style="box-sizing: border-box">僵尸<rt style="box-sizing: border-box">zombie</rt></ruby>”状态。从父进程角度看,子进程仍然存在,即使子进程实际上已经死亡。这就是“<ruby style="box-sizing: border-box">僵尸进程<rt style="box-sizing: border-box">zombie process</rt></ruby>”(也被称为“<ruby style="box-sizing: border-box">已消失进程<rt style="box-sizing: border-box">defunct process</rt></ruby>”)是如何产生并存在于系统中的。

这里有一个来自 Turnoff.us [2] 的关于僵尸进程的非常有趣的看法:

Image credit: Turnoff.us

重点要说的是,僵尸进程并没有像它的名称那样看起来可怕。

但如果系统的内存已经所剩不多或者有太多的僵尸进程在吃掉内存,问题会变得糟糕。同样,大部分 Linux 系统进程最大 PID 设置为 32768,如果过多僵尸进程导致其他重要任务没有 PID 可用,你的系统会发生崩溃。

这是真实可能发生的,它有一定的概率,特别当存在一个编码糟糕的程序开始大量产生僵尸进程的时候。

在这种情况下,找到并杀死僵尸进程是一个明智的做法。

Linux 系统中的进程可能处于如下状态中的一种:

那如何查看进程和它的当前状态呢?一个简单的方法是在终端中使用 top 命令 [3]。

Top command show processes and their status

正如你在上面截图中看到的,截图中共有 250 个任务(进程),其中 1 个处在 “<ruby style="box-sizing: border-box">运行中<rt style="box-sizing: border-box">running</rt></ruby>” 状态,248 个进程处于 “<ruby style="box-sizing: border-box">休眠<rt style="box-sizing: border-box">sleep</rt></ruby>” 状态,还有一个处于 “<ruby style="box-sizing: border-box">僵尸<rt style="box-sizing: border-box">zombie</rt></ruby>” 状态。

现在问题进入下一步,如何杀死 “僵尸” 进程?

僵尸进程已经死了,要如何才能杀死一个已经死亡的进程呢?

在僵尸电影中,你可以射击僵尸的头部或烧掉它们,但在这里是行不通的。你可以一把火烧了系统来杀死僵尸进程,但这并不是一个可行的方案。

一些人建议发送 SIGCHLD 给父进程,但这个信号很可能会被忽略。还有一个方法是杀死父进程来杀死僵尸进程,这听起来很野蛮,但它却是唯一能确保杀死僵尸进程的方法。

首先,通过在终端中 使用 ps 命令 [4] 我们列举僵尸进程,得到它们的进程 ID:

<pre class="prettyprint linenums" style="box-sizing: border-boxoverflow: hiddenfont: 400 12px / 20px "courier new"display: blockpadding: 10px 15pxmargin: 20px 0pxcolor: rgb(248, 248, 212)word-break: break-alloverflow-wrap: break-wordbackground: rgb(39, 40, 34)border: noneborder-radius: 4pxbox-shadow: rgb(57, 56, 46) 40px 0px 0px inset, rgb(70, 71, 65) 41px 0px 0px insetletter-spacing: normalorphans: 2text-align: starttext-indent: 0pxtext-transform: nonewidows: 2word-spacing: 0px-webkit-text-stroke-width: 0pxtext-decoration-thickness: initialtext-decoration-style: initialtext-decoration-color: initial">

</pre>

ps ux 命令输出的第 8 列显示了进程状态。上述命令只会打印所有处在 Z+ 状态(表示僵尸状态)的进程。

确认了进程 ID 后,我们可以得到它的父进程 ID:

<pre class="prettyprint linenums" style="box-sizing: border-boxoverflow: hiddenfont: 400 12px / 20px "courier new"display: blockpadding: 10px 15pxmargin: 20px 0pxcolor: rgb(248, 248, 212)word-break: break-alloverflow-wrap: break-wordbackground: rgb(39, 40, 34)border: noneborder-radius: 4pxbox-shadow: rgb(57, 56, 46) 40px 0px 0px inset, rgb(70, 71, 65) 41px 0px 0px insetletter-spacing: normalorphans: 2text-align: starttext-indent: 0pxtext-transform: nonewidows: 2word-spacing: 0px-webkit-text-stroke-width: 0pxtext-decoration-thickness: initialtext-decoration-style: initialtext-decoration-color: initial">

</pre>

你也可以将上述两个命令结合在一起,直接得到僵尸进程的 PID 及其父进程的 PID:

<pre class="prettyprint linenums" style="box-sizing: border-boxoverflow: hiddenfont: 400 12px / 20px "courier new"display: blockpadding: 10px 15pxmargin: 20px 0pxcolor: rgb(248, 248, 212)word-break: break-alloverflow-wrap: break-wordbackground: rgb(39, 40, 34)border: noneborder-radius: 4pxbox-shadow: rgb(57, 56, 46) 40px 0px 0px inset, rgb(70, 71, 65) 41px 0px 0px insetletter-spacing: normalorphans: 2text-align: starttext-indent: 0pxtext-transform: nonewidows: 2word-spacing: 0px-webkit-text-stroke-width: 0pxtext-decoration-thickness: initialtext-decoration-style: initialtext-decoration-color: initial">

</pre>

现在你得到了父进程 ID,使用命令行和得到的 ID 号 终于可以杀死进程了 [5]:

<pre class="prettyprint linenums" style="box-sizing: border-boxoverflow: hiddenfont: 400 12px / 20px "courier new"display: blockpadding: 10px 15pxmargin: 20px 0pxcolor: rgb(248, 248, 212)word-break: break-alloverflow-wrap: break-wordbackground: rgb(39, 40, 34)border: noneborder-radius: 4pxbox-shadow: rgb(57, 56, 46) 40px 0px 0px inset, rgb(70, 71, 65) 41px 0px 0px insetletter-spacing: normalorphans: 2text-align: starttext-indent: 0pxtext-transform: nonewidows: 2word-spacing: 0px-webkit-text-stroke-width: 0pxtext-decoration-thickness: initialtext-decoration-style: initialtext-decoration-color: initial">

</pre>

Killing parent process

再次运行 ps 命令或 top 命令,你可以验证僵尸进程是否已经被杀死。

恭喜!现在你知道怎么清理僵尸进程了。

via: https://itsfoss.com/kill-zombie-process-linux/

刚开始入门的时候都比较迷茫, 觉得 C 好像没有 GUI 就感觉什么也做不了一样. 事实上是 C 什么都可以做.

我之谈谈自己接触过的一些东西.

1. 图形处理 (OpenCV 里面都是 C 代码)

2. openkinect (同样是用 C 完成应用开发)

3. 在 Linux 平台上 GTK+ 应用程序的开发

4. 自然语言处理 (MeCab, 日本京都大学开发的, 里面也全部是 C 语言)

5. 太多的基于 C 语言的开放项目了, 数不清.

6. 声音信号的生成

7. 很多情况是用 C 写的 API, 然后用 swig 进行 warpper, 可以从 ruby, perl, python 等进行调用

什么都能做, 好好加油吧. 我的个人经验, 学完 C/C++, Java 其余语言都是相通的, 上手很快.

我自己熟悉的语言超过 10 种以上.

LISP (CommonLISP, Scheme), 普通用户不推荐, 大师级别可以考虑.

Fortran 很多人以为过时了, 其实根本不是, 本人接触的一些科研项目里面经常有 fortran 的身影.

语言只是一个工具, 关键是算法设计.

还有就是每天要养成写程序的习惯, 要不然很容易生分, 而且没有感觉, 我说的感觉就是, 看到代码以后可以很快的找出错误.

我的思维很混乱, 讲究看吧.

首先,要学Linux编程,你得会用Linux,也就是得在命令行环境下生存下来。什么叫生存下来呢?就是我现在给你一台主机,键盘,显示器啥的,然后给你一个服务器版的Linux系统的光盘或者其他什么安装盘,你去把这台主机用起来。什么叫用起来呢?你平常用Windows电脑干啥,你现在还用这台电脑干啥。新建文件啊,查看文件,编辑文件,保存文件,复制,移动,删除,打包,解压,联网,下载个什么东西啊等等基本操作你得会。还有软件怎么安装,不仅要熟悉apt-get和yum,还有给你源码的软件怎么安装你得会,另外要熟悉Linux下的文件系统,每个目录是干啥的,目录下的文件是干嘛的,插入一个U盘,如何挂载这个U盘,操作U盘下的文件你得会啊。这个看一本书就行了,《鸟哥的Linux私房菜-基础篇》,记得是基础篇,记得安装Linux系统自己操作一遍,还有一本是服务器篇,你既然是要学Linux编程开发,那就不用看服务器架设篇了。做完这一步,你可以开发了。

Linux下开发,两种基本语言,C和C++咯,至于其他人要说Python,Java,Ruby啥的不讨论,因为就讨论Linux下的开发,什么是Linux开发呢?就是利用Linux的API进行开发咯,首先你得会C语言或者C++语言啊,这个去看丹尼斯的《C程序设计语言》,注意是丹尼斯的,C++的就去看《Essential C++》或者《C++ Primer》,然后在Linux下的程序开发,Linux的API是遵循POSIX标准的,自行谷歌什么叫POSIX。Linux下程序开发几大块,文件操作,这个很重要,你要知道Linux下的一个思想叫一切皆文件,可见文件读写多重要了。I/O模型,五大I/O模型,阻塞,非阻塞,复用,信号驱动和异步I/O,环环相扣丝丝相连,概念和操作都要仔细琢磨,最重要的当属复用,就是select,poll和epoll,面试笔试就问这个东西,要知道他们的适用范围和优缺点。进程和线程,包括进程和线程的概念和区别,进程和线程的建立,同步,通信,互斥等等。网络编程,就是socket编程,Linux编程,这个学不好等于啥都没学,这个估计还得了解一下TCP/IP协议,编程方面主要是那几步,申请socket,bind,listen,accept几步,要熟悉种常见的服务器模型,进程池线程池方式的,多进程方式的,复用方式的,最重要的是复用方式的,这部分可以先只写服务器,测试直接用Telnet就好了,加快速度么。其余的就是数据库,这个东西不属于Linux,但是还得会,要不然啥都做不了,看那本《MySQL必知必会》,当然深入的话还得找本专业的书细细看。这个时候就可以真刀真枪的去干点有意思的事了,比如写个终端下的类似于QQ的软件啊,包括服务器和客户端啊,慢慢的增加并发数,比如可以同时支持五千人在线啊,文件传输啊等等。然后学学Qt,熟悉一下图形界面,可以把你的终端下的QQ完全改成图形界面下的。估计到这个时候,你差不多在Linux下进行像样的开发了吧。在这个过程的学习中,相信你已经学会Makefile的编写啊,编译啊,链接啊等等一些细枝末节的东西了,还得反思一下把零散的东西串一串,要系统化。

接下来就是继续深入了,Linux为什么这么多人用,好处在哪里,你得去稍微的看看内核源码啊,内核的进线程调度啊,我告诉你,Linux内核的一个链表都够你研究好几节课的。哦,这个时候,数据结构啥的又得翻出来加强一下了不是,计算机网络啥的也得看看,操作系统原理啥的也得看看呢不是,把这些东西放在这里是合适的,前面让你知其然,知道怎么编程怎么做,现在要知其所以然了不是。

在学习的过程中,要不断积累和了解最新的东西,最起码要知道个概念,比如分布式,大数据,云计算,机器学习,计算机视觉,JIT等等,形成知识链,这样不会导致你最后不知道学啥。有个建议,一定要学一下Python,一定要学一下Python,一定要学一下Python,重要的事情说三遍。它能极大的提高你的工作效率,也能和C/C++结合在一起用,很nice的语言。

最后推荐几本书(前面的包含在内):

《鸟哥的Linux私房菜 基础篇》

《C程序设计语言》 丹尼斯写的

《Linux C编程一站式学习》 宋劲杉写的

《Eensstial C++》

《C++ Primer》

《Effective C++》

《Linux网络编程》 宋劲彬写的

《Unix环境高级编程》

《Unix网络编程》 两部

《Linux高级程序设计》 华清远见的

《MySQL必知必会》

《数据库系统概念》

《大话数据结构》

《算法导论》

《Linux内核情景分析》

《深入理解Linux内核》

《深入理解计算机系统》

《现代操作系统》

《深入理解计算机网络》

《TCP/IP》的三卷经典书