man ps 中描述D状态是Uninterruptible Sleep
Linux进程有两种睡眠状态,
- Interruptible Sleep(可中断睡眠,在ps命令中显示“S”)。处在这种睡眠状态的进程是可以通过给它发送signal来唤醒的,比如发HUP信号给nginx的master进程可以让nginx重新加载配置文件而不需要重新启动nginx进程;
- Uninterruptible Sleep(不可中断睡眠,在ps命令中显示“D”)。处在这种状态的进程不接受外来的任何signal,这也是为什么之前我无法用kill杀掉这些处于D状态的进程,无论是“kill”, “kill -9”还是“kill -15”,因为它们压根儿就不受这些信号的支配。
进程为什么会被置于D状态呢?处于uninterruptible sleep状态的进程通常是在等待IO,比如磁盘IO,网络IO,其他外设IO,如果进程正在等待的IO在较长的时间内都没有响应,那么就很会不幸地被ps看到了,同时也就意味着很有可能有IO出了问题,可能是外设本身出了故障,也可能是比如NFS挂载的远程文件系统已经不可访问了。
正是因为得不到IO的响应,进程才进入了uninterruptible sleep状态,所以要想使进程从uninterruptible sleep状态恢复,就得使进程等待的IO恢复,比如如果是因为从远程挂载的NFS卷不可访问导致进程进入uninterruptible sleep状态的,那么可以通过恢复该NFS卷的连接来使进程的IO请求得到满足,除此之外,要想干掉处在D状态进程就只能重启整个Linux系统了(恐怖的D状态)。
看到有人说如果要想杀掉D状态的进程,通常可以去杀掉它的父进程(通常是shell,我理解的这种情况是在shell下直接运行的该进程,之后该进 程转入了D状态),于是我就照做了,之后就出现了上面的状态:他们的父进程被杀掉了,但是他们的父进程PID都变成了1,也就是init进程,这下可如何是好?此时我这些D状态的进程已经影响到其他一些进程的运行,而已经无法访问的NFS卷又在段时间内无法恢复,那么,只好重新启动了。
PS:Linux进程状态列表
状态 |
定义 |
R |
Running.运行中 |
S |
Interruptible Sleep.等待调用 |
D |
Uninterruptible Sleep.等待磁盘IO |
T |
Stoped.暂停或者跟踪状态 |
X |
Dead.即将被撤销 |
Z |
Zombie.进程已经结束,仅映像名留存 |
W |
Paging.内存交换 |
N |
优先级低的进程 |
< |
优先级高的进程 |
s |
进程的领导者 |
L |
锁定状态 |
l |
多线程状态 |
+ |
前台进程 |