如何杀掉D,Z状态的进程

D,Z状态进程简介

长期生活在 Linux 环境里,渐渐地就有一种环保意识油然而生。比如,我们会在登录提示里写上“悟空,我跟你说过叫你不要乱扔东西,乱扔东西是不对的。哎呀我话没说完你怎么把棍子扔掉了?月光宝盒是宝物,乱扔它会污染环境,要是砸到小朋友怎么办?就算砸不到小朋友,砸到了花花草草也不好嘛...”;在用户缺省目录里放一个题为 “自觉保护环境 请勿堆放垃圾”的空文件,并用 chattr +i 设为不可修改;看到垃圾文件就立即扫入 /tmp 目录,然后发广播通知垃圾制造者自己去 /tmp 认领,且警告其下不为例...我们深知,系统环境的整洁有利于系统管理员保持良好的心情、清晰的思路和稳定的工作状态。

  有一类垃圾却并非这么容易打扫,那就是我们常见的状态为 D (Uninterruptible sleep) ,以及状态为 Z (Zombie) 的垃圾进程。这些垃圾进程要么是求而不得,像怨妇一般等待资源(D),要么是僵而不死,像冤魂一样等待超度(Z),它们在 CPU run_queue 里滞留不去,把 Load Average 弄的老高老高,没看过我前一篇blog的国际友人还以为这儿民怨沸腾又出了什么大事呢。怎么办?开枪!kill -9!看你们走是不走。但这两种垃圾进程偏偏是刀枪不入的,不管换哪种枪法都杀不掉它们。无奈,只好reboot,像剿灭禽流感那样不分青红皂白地一律扑杀!

悟空,我们所运维的可是24*7全天候对外部客户服务的系统,怎么能动不动就 reboot ?我们的考核指标可是4个9(99.99%,全年计划外当机时间不得超过52分钟34秒),又不是4个8,你稍微遇到点事就reboot,还要不要可用性了?再说,现在社会都开始奔和谐去了,我们对于 D 和 Z 这两种垃圾进程,也该尽可能采取慈悲手段,能解决其困难的,就创造条件,解决其实际困难,能消除其冤结的,就诵经烧纸,消除其前世冤结,具体问题应具体分析具体解决,滥杀无辜只会导致冤冤相报因果循环...$^#$%#%^@#

贫僧还是回来说正题。怨妇 D,往往是由于 I/O 资源得不到满足,而引发等待,在内核源码 fs/proc/array.c 里,其文字定义为“ "D (disk sleep)", /* 2 */ ”(由此可知 D 原是Disk的打头字母),对应着 include/linux/sched.h 里的“ #define TASK_UNINTERRUPTIBLE 2 ”。举个例子,当 NFS 服务端关闭之时,若未事先 umount 相关目录,在 NFS 客户端执行 df 就会挂住整个登录会话,按 Ctrl+C 、Ctrl+Z 都无济于事。断开连接再登录,执行 ps axf 则看到刚才的 df 进程状态位已变成了 D ,kill -9 无法杀灭。正确的处理方式,是马上恢复 NFS 服务端,再度提供服务,刚才挂起的 df 进程发现了其苦苦等待的资源,便完成任务,自动消亡。若 NFS 服务端无法恢复服务,在 reboot 之前也应将 /etc/mtab 里的相关 NFS mount 项删除,以免 reboot 过程例行调用 netfs stop 时再次发生等待资源,导致系统重启过程挂起。

冤魂 Z 之所以杀不死,是因为它已经死了,否则怎么叫 Zombie(僵尸)呢?冤魂不散,自然是生前有结未解之故。在UNIX/Linux中,每个进程都有一个父进程,进程号叫PID(Process ID),相应地,父进程号就叫PPID(Parent PID)。当进程死亡时,它会自动关闭已打开的文件,舍弃已占用的内存、交换空间等等系统资源,然后向其父进程返回一个退出状态值,报告死讯。如果程序有 bug,就会在这最后一步出问题。儿子说我死了,老子却没听见,没有及时收棺入殓,儿子便成了僵尸。在UNIX/Linux中消灭僵尸的手段比较残忍,执行 ps axjf 找出僵尸进程的父进程号(PPID,第一列),先杀其父,然后再由进程天子 init(其PID为1,PPID为0)来一起收拾父子僵尸,超度亡魂,往生极乐。注意,子进程变成僵尸只是碍眼而已,并不碍事,如果僵尸的父进程当前有要务在身,则千万不可贸然杀之。 

关于ZOMBIE进程:

这些进程已经死亡,但没有释放系统资源,包括内存和一些一些系统表等,如果这样的进程很多,会引发系统问题。用ps -el看出的进程状态如果是Z,就是僵尸进程。
ps -ef|grep defunc可以找出僵尸进程.
有些ZOMBIE进程时用kill -9也不能杀死,而且消耗了很多系统资源不能释放,如果系统在shutdown时发出信息:some process wouldn’t die. 这就意味这有些进程不能被reboot发出的kill –9杀掉,这些很可能就是僵尸进程。

可以用ps 的 – l 选项,得到更详细的进程信息. 
F(Flag):一系列数字的和,表示进程的当前状态。这些数字的含义为: 
00:若单独显示,表示此进程已被终止。 
01:进程是核心进程的一部分,常驻于系统主存。如:    sched、 vhand 、bdflush 等。 
02:Parent is tracing process. 
04 :Tracing parent's signal has stopped the process; the parent is waiting ( ptrace(S)). 
10:进程在优先级低于或等于25时,进入休眠状态,而且不能用信号唤醒,例如在等待一个inode被创建时    
20:进程被装入主存(primary memory) 
40:进程被锁在主存,在事务完成前不能被置换   e 
S(state of the process ) 
O:进程正在处理器运行  
S:休眠状态(sleeping) 
R:等待运行(runable)    
I:空闲状态(idle) 
Z:僵尸状态(zombie)    
T:跟踪状态(Traced) 
B:进程正在等待更多的内存页 
C(cpu usage):cpu利用率的估算值

清除ZOMBIE(僵尸)进程可以使用如下方法:
1> kill –18 PPID (PPID是其父进程)
这个信号是告诉父进程,该子进程已经死亡了,请收回分配给他的资源。
2>如果不行则看能否终止其父进程(如果其父进程不需要的话)。先看其父进程又无其他子进程,如果有,可能需要先kill其他子进程,也就是兄弟进程。方法是:
kill –15 PID1 PID2(PID1,PID2是僵尸进程的父进程的其它子进程)。
然后再kill父进程:kill –15 PPID

这样僵尸进程就可能被完全杀掉了。

杀掉D状态进程

       基本想法就是修改内核,遍历 进程 列表,找到处于D 状态 进程 ,将其 状态 转换为别的 状态 就可以kill掉了。 
这是一种比较粗鲁的方法,可能会引起一些不良后果,暂时没有考虑。对于确切知道已经没有什么用处,不用做清理工作的,处于D 状态 怎么也杀不死的 进程 来说,确是很有效。 
内核模块代码: 
—————-killd.c—————- 
#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/sched.h> //for_each_process 
MODULE_LICENSE("BSD"); 
static int pid = -1; 
module_param(pid, int, S_IRUGO); 
static int killd_init(void) 

    struct task_struct * p; 
    printk(KERN_ALERT "killd: force D status process to death/n"); 
    printk(KERN_ALERT "killd: pid=%d/n", pid); 
    //read_lock(&tasklist_lock); 
    for_each_process(p){ 
        if(p->pid == pid){ 
            printk("killd: found/n"); 
            set_task_state(p, TASK_STOPPED); 
            printk(KERN_ALERT "killd: aha, dead already/n"); 
            return 0; 
        } 
    } 
    printk("not found"); 
    //read_unlock(&tasklist_lock); 
    return 0; 

static void killd_exit(void) 

    printk(KERN_ALERT "killd: bye/n"); 

module_init(killd_init); 
module_exit(killd_exit); 
—–Makefile———— 
obj-m := killd.o 
编译模块 
make -C yourkerneltree M=`pwd` modules 
插入模块的时候提供D 状态 进程 号,就可以将其转换为stopped 状态 ,使用普通kill就可以杀死。 

./insmod ./killd.ko pid=1234

http://www.verydemo.com/demo_c167_i86771.html

http://blog.csdn.net/eroswang/article/details/1774298


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值