进程的disk sleep状态与僵尸进程

标签: | 发表时间:2023-05-04 14:08 | 作者:
出处:https://blog.csdn.net

先说一下进程的状态

1.1)Running(R),运行或将要运行
1.2)Interruptible(S),被阻断而等待一个事件,可能会被一个信号激活
1.3)Uninterruptible(D),被阻断而等待一个事件,不会被信号激活
1.4)Stopped(T),由于任务的控制或者外部的追踪而被终止,比如:strace
1.5)Zombie(Z),僵死,但是它的父进程尚未调用wait函数.
1.6)Deal(X),这个永远看不见

睡眠状态

Linux进程有两种睡眠状态,一种interruptible sleep,处在这种睡眠状态的进程是可以通过给它发信号来唤醒的,也是可以kill的,进程状态如下

[root@lmxe:/home]#cat /proc/949/status
Name:   sysmgt
State:  S (sleeping)

另外一种睡眠状态是uninterruptible sleep,处在这种状态的进程不接受外来的任何信号,这也是为什么之前我无法用kill杀掉这些处于D状态的进程,无论是”kill”, “kill -9″还是”kill -15″,因为它们压根儿就不受这些信号的支配。

[root@lmxe:/home]#cat /proc/949/status
Name:   sysmgt
State:  D (disk sleeping)

进程为什么会被置于uninterruptible sleep状态呢?处于uninterruptible sleep状态的进程通常是在等待IO,比如磁盘IO,网络IO,其他外设IO,如果进程正在等待的IO在较长的时间内都没有响应,那么就很会不幸地被 ps看到了,同时也就意味着很有可能有IO出了问题,可能是外设本身出了故障,也可能是比如挂载的远程文件系统已经不可访问了,我这里遇到的问题就是由互斥锁引起的,比如说我开了8个进程同时访问一个io,访问的时候势必会加锁来保护资源,那么,当一个进程正在访问的时候,其他进程如果在等待锁,那么就会进入disk sleep,当你执行kill,它不会立即响应,当锁满足条件的时候才可能响应信号。

僵尸进程

当我杀死一个子进程,而父进程又处于disk sleep时,那么子进程就会变为无人收尸的僵尸进程。子进程从运行直至其终止,从内存中移除,但进程描述符仍然保留在内存中(进程描述符占有极少的内存空间)。子进程的状态变成 EXIT_ZOMBIE,并且向父进程发送SIGCHLD 信号,父进程此时应该调用  wait() 系统调用来获取子进程的退出状态以及其它的信息。在 wait 调用之后,僵尸进程就完全从内存中移除。因此一个僵尸存在于其终止到父进程调用 wait 等函数这个时间的间隙,一般很快就消失,但如果编程不合理,父进程从不调用 wait 等系统调用来收集僵尸进程,那么这些进程会一直存在内存中。

根据上面的描述,我们很容易去写一个程序来产生僵尸进程,如下代码:

#include <stdio.h>
#include <sys/types.h>

int main()
{
    //fork a child process
    pid_t pid = fork();

    if (pid > 0)   //parent process
    {
        printf("in parent process, sleep for one miniute...zZ...\n");
        sleep(60);
        printf("after sleeping, and exit!\n");
    }
    else if (pid == 0)  
    {
        //child process exit, and to be a zombie process
        printf("in child process, and exit!\n");
        exit(0);
    }

    return 0;
}
    
系统中多了一个僵尸进程。但如果等父进程睡眠醒来退出之后,我们再次查看系统进程信息,发现刚才的僵尸进程不见了。

怎样避免僵尸进程的产生

不能使用 kill 后接  SIGKILL 信号这样的命令像杀死普通进程一样杀死僵尸进程,因为僵尸进程是已经死掉的进程,它不能再接收任何信号。事实上,如果系统中僵尸进程并不多的话,我们也无需去消除它们,少数的僵尸进程并不会对系统的性能有什么影响。

那么在编程时,如果能避免系统中大量产生僵尸进程呢?根据上面描述的,子进程在终止时会向父进程发 SIGCHLD 信号,Linux 默认是忽略该信号的,我们可以显示安装该信号,在信号处理函数中调用 wait 等函数来为其收尸,这样就能避免僵尸进程长期存在于系统中了。示例代码如下:

#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>

sig_atomic_t child_exit_status;

void clean_up_child_process(int signal_num)
{
    /* clean up child process */
    int status;
    wait (&status);

    /* store its exit status in a global variable */
    child_exit_status = status;
}

int main()
{
    /* handle SIGCHLD by calling clean_up_child_process  */
    struct sigaction sigchild_action;
    memset(&sigchild_action, 0, sizeof(sigchild_action));
    sigchild_action.sa_handler = &clean_up_child_process;
    sigaction(SIGCHLD, &sigchild_action, NULL);

    /* fork a child, and let the child process dies before parent */
    pid_t c_pid;
    c_pid = fork();
    if (c_pid > 0)
    {
        printf("in parent process, and sleep for on mininute...zZ...\n");
        sleep(60);
    }
    else if(c_pid == 0)
    {
        printf("in child process, and exit now\n");
        exit(0);
    }
    else
    {
        printf("fork failed!\n");
    }

    return 0;
}   
    

相关 [进程 disk sleep] 推荐:

进程的disk sleep状态与僵尸进程

- -
1.1)Running(R),运行或将要运行. 1.2)Interruptible(S),被阻断而等待一个事件,可能会被一个信号激活. 1.3)Uninterruptible(D),被阻断而等待一个事件,不会被信号激活. 1.4)Stopped(T),由于任务的控制或者外部的追踪而被终止,比如:strace.

【ActiveMQ Tuning】Serializing to Disk

- - 博客园_首页
     翻译自: http://fusesource.com/docs/broker/5.4/tuning/PersTuning-SerialToDisk.html.      KahaDB message store:KahaDB 是ActiveMQ Broker 为了高性能而推荐使用的消息存储机制.

wait、sleep、yield区别

- - CSDN博客推荐文章
1、属于Object的本地方法. 2、暂停当前线程,并释放锁. 3、调用notify()或notifyAll()方法唤醒线程. 1、Thread类的静态方法. 2、当前线程休眠,但不释放锁. 3、其他线程可以继续执行,无论该线程优先级高与否. 4、休眠一段时间后,自动执行. 1、Thread类的静态方法.

排序算法 Sleep Sort

- Jeff - 酷壳 - CoolShell.cn
排序算法好像是程序员学习编程最多的算法,也可能是算法研究者们最喜欢研究的算法了. 排序有很多很多的算法,比如,冒泡,插入,选择,堆,快速,归并等等(你可以看看本站以前的那些文章:可视化的排序,排序算法比较,显示排序过程的python)这里向大家介绍一个“巨NB”的排序算法——Sleep Sort. 闲言少说,请看下面的代码(用Shell脚本写的).

Java Sleep() 与 Wait()的机制原理与区别

- - CSDN博客推荐文章
Java中的多线程是一种抢占式的机制而不是分时机制. 线程主要有以下几种状态:可运行,运行,阻塞,死亡. 抢占式机制指的是有多个线程处于可运行状态,但是只有一个线程在运行.        当有多个线程访问共享数据的时候,就需要对线程进行同步.        Thread类的方法:sleep(),yield()等.

[转载]java之yield(),sleep(),wait()区别详解

- - 移动开发 - ITeye博客
使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁. 也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据. 例如有两个线程同时执行(没有synchronized)一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有Sleep()方法,只有高优先级的线程执行完毕后,低优先级的线程才能够执行;但是高优先级的线程sleep(500)后,低优先级就有机会执行了.

Disk SpeedUP – 磁盘碎片整理软件 | 小众软件 > 系统工具

- tom - 小众软件 - Appinn
Disk Speed 具有单独、批量整理磁盘碎片,也可以设置整理计划或在系统空闲时整理. 相对于 Defraggler 来说,批量整理和排除文件应该是比较实用的功能了. 这个软件实在精炼、易用,竟然没什么需要赘述的……. update: 感谢网友“过客”提供中文语言文件. uushare | 官方主页 | 来自小众软件 | skydrive.

特征向量内存快速查找库 GitHub - spotify/annoy: Approximate Nearest Neighbors in C++/Python optimized for memory usage and loading/saving to disk

- -
还有一些其他库可以进行最近邻搜索. Annoy几乎和最快的库一样快(见下文),但实际上还有另一个功能让Annoy与众不同:它能够将静态文件用作索引. 特别是,这意味着您可以跨进程共享索引. Annoy还将创建索引与加载它们分离,因此您可以将索引作为文件传递并快速映射到内存中. Annoy的另一个好处是它试图最小化内存占用,因此索引非常小.

监控进程

- - 火丁笔记
有时候,进程突然终止服务,可能是没有资源了,也可能是意外,比如说:因为 OOM 被杀;或者由于 BUG 导致崩溃;亦或者误操作等等,此时,我们需要重新启动进程. 实际上,Linux 本身的初始化系统能实现简单的功能,无论是老牌的 SysVinit,还是新潮的  Upstart 或者  Systemd 均可,但它们并不适合处理一些复杂的情况,比如说:CPU 占用超过多少就重启;或者同时管理 100 个 PHP 实现的 Worker 进程等等,如果你有类似的需求,那么可以考虑试试 Monit 和 Supervisor,相信会有不一样的感受.

Linux进程关系

- - 博客园_首页
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明. Linux的进程相互之间有一定的关系. 比如说,在 Linux进程基础中,我们看到,每个进程都有父进程,而所有的进程以init进程为根,形成一个树状结构. 我们在这里讲解进程组和会话,以便以更加丰富的方式了管理进程.