linux进程状态D和Z的处理

本文探讨了Linux环境中进程状态D(Uninterruptible sleep)和Z(Zombie)的问题及解决方案。D状态通常因I/O资源等待引起,正确做法是恢复所需服务或资源;Z状态源于进程终止但未被父进程正确处理,解决方法是找到并处理其父进程。

原贴:http://www.lupaworld.com/94908/viewspace-60895.html

linux进程状态D和Z的处理

上一篇 / 下一篇  2008-05-21 16:44:05 / 个人分类:linux编程

长期生活在 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)来一起收拾父子僵尸,超度亡魂,往生极乐。注意,子进程变成僵尸只是碍眼而已,并不碍事,如果僵尸的父进程当前有要务在身,则千万不可贸然杀之。
备注:
PROCESS STATE CODES
Here are the different values that the s, stat and state output specifiers
(header "STAT" or "S") will display to describe the state of a process.
D Uninterruptible sleep (usually IO)
R Running or runnable (on run queue)
S Interruptible sleep (waiting for an event to complete)
T Stopped, either by a job control signal or because it is being traced.
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z Defunct ("zombie") process, terminated but not reaped by its parent.

For BSD formats and when the stat keyword is used, additional characters may
be displayed:
< high-priority (not nice to other users)
N low-priority (nice to other users)
L has pages locked into memory (for real-time and custom IO)
s is a session leader
l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
+ is in the foreground process group

TAG:

引用 删除 Guest   /   2009-05-22 16:37:51
-5
超级玛丽 引用 删除 ckhitler   /   2009-05-19 19:13:54
不错。我之前也写过这样的文章,进程有6种状态,分别是(z,x,s,d,t,r),UNIX是一套伟大的系统.
引用 删除 gnufeng   /   2008-09-13 08:13:30
对D状态的处理好像还不完全啊,有没有办法让进程永远没有D状态呢?
仰空冥思 引用 删除 陈莉君   /   2008-05-21 23:15:31
### 进程状态 R(运行状态进程状态 `R` 表示该进程当前处于“运行”或“可执行”状态。这意味着进程正在 CPU 上执行,或者已经准备好执行,正在等待被调度器选中运行。Linux 内核中将运行就绪状态统一为 `TASK_RUNNING` 状态,区别于一些其他操作系统中将两者分开的做法。只有处于 `R` 状态进程才可能被调度到 CPU 上运行,多个进程可以同时处于该状态,它们的进程控制块(PCB)会被组织在对应 CPU 的可执行队列中[^4]。 例如,以下程序会创建一个持续运行的进程: ```c #include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { while(1) { int a = 1; a += 1; } return 0; } ``` 编译并运行该程序后,使用 `ps` 命令可以观察到该进程状态为 `R`: ```bash ps -eo pid,stat,comm | grep a.out ``` ### 进程状态 D(不可中断睡眠状态进程状态 `D` 表示“不可中断睡眠”状态(`TASK_UNINTERRUPTIBLE`),该状态下的进程正在等待某些特定的硬件资源完成操作,例如等待磁盘 I/O 完成。与 `S` 状态不同的是,处于 `D` 状态进程不会响应信号,因此无法通过 `kill` 命令终止。这种设计是为了保证某些关键系统调用的完整性,防止进程在资源未释放前被中断[^5]。 例如,当进程请求进行磁盘写入操作时,在磁盘完成写入并返回结果之前,该进程将进入 `D` 状态。由于其不可中断特性,若系统中存在大量 `D` 状态进程,可能会影响系统整体响应能力,甚至导致挂起现象。 ### 进程状态 Z(僵尸状态进程状态 `Z` 表示“僵尸状态”(`TASK_ZOMBIE`),即该进程已经执行完毕并终止,但其父进程尚未调用 `wait()` 或 `waitpid()` 系统调用来回收其退出状态信息。此时,该进程进程控制块(PCB)仍然保留在系统中,仅释放了用户空间的资源,因此它不会消耗 CPU 或内存资源,但仍占用一个进程 ID[^3]。 如果父进程长期不回收子进程的退出信息,系统中将积累大量僵尸进程,这可能导致进程表资源耗尽,影响新进程的创建。为了避免这一问题,通常建议父进程正确处理进程的退出状态,或在必要时将子进程交由 `init` 进程(PID 为 1)接管,使其自动回收。 例如,可以通过以下方式演示僵尸进程的产生: ```c #include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { pid_t pid = fork(); if (pid == 0) { // 子进程退出 exit(0); } else { // 父进程不调用 wait,导致子进程成为僵尸进程 sleep(60); } return 0; } ``` 在子进程退出后,使用 `ps` 命令查看其状态: ```bash ps -eo pid,stat,comm ``` 可以观察到子进程状态为 `Z`,表示其已进入僵尸状态
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值