Linux 进程状态
进程状态
top里面S列表示进程状态。
R |
正在运行或者等待运行(Running或Runnable),进程在CPU的就绪队列中。 |
D |
硬件交互导致的不可中断睡眠状态(Uninterruptible Sleep),进程正在与硬件交互。 |
Z |
僵尸进程(Zombie),虽然进程已经结束,但是父进程没有回收它的资源。父进程回收它的资源后会消亡;或者父进程退出后,init进程回收后也会消亡。 |
S |
可中断睡眠状态(Interruptible Sleep),进程因等待而挂起,唤醒后进入R状态。 |
I |
不可中断睡眠的空闲状态(Idle)。D状态进程会使平均负载升高,I状态进程不会。 |
T |
停止状态(stopped),不响应请求,发送SIGSTOP或者SIGTSTP信号来停止进程,发送SIGCONT信号让进程继续运行。其中,SIGSTOP和SIGTSTP信号区别在于,SIGSTOP信号不能捕获。 kill -19暂停进程,kill -18进程继续执行。 |
不可中断进程和僵尸进程案例
代码路径是https://github.com/feiskyer/linux-perf-examples/tree/master/high-iowait-process。
cd linux-perf-examples/high-iowait-process
构建镜像:make build
本地机器:docker run --privileged --name=app -itd feisky/app:iowait
执行top
根据Tasks这一行,有4个正在运行的进程,220个僵尸进程,而且僵尸进程的数量还在不断增加,说明有子进程退出时父进程没清理对应的资源。
通过ps aux | grep Z来寻找僵尸进程。
通过pstree -aps | grep 3381来寻找僵尸进程的父进程。
确认app应用代码是否存在问题,找到子进程的创建和清理位置
int status = 0;
for (;;) {
for (int i = 0; i < 2; i++) {
if(fork()== 0) {
sub_process();
}
}
sleep(5);
}
while(wait(&status)>0);
wait函数等待子进程结束没被调用到,把它挪到for循环里面。
int i = 0;
for (;;)
{
for (i = 0; i < 2; i++)
{
if (fork() == 0)
{
sub_process(disk, buffer_size, buffer_count);
}
}
while (wait(&status) > 0);
sleep(5);
}
子进程结束运行后,如果父进程没有调用wait或者waitpid来获取子进程的状态,内核无法释放内存中的子进程PCB,那么子进程成为僵尸进程。
fork出来的子进程和父进程同名,prctl设置的进程名只有在子进程死后或者变成僵尸进程时才显示。