在https://editor.csdn.net/md/?articleId=138925446这篇文章中,我缺失了关于僵尸进程的处理办法的内容,因为当时脑子不好的小菜鸟并未学到这里,现在就让我填上这个坑🕳吧😉
在知道僵尸进程的处理办法之前,请让我们思考以下问题
答案:进程状态1为Z的就是僵尸进程(不知道怎么查看进程状态的可以点击“进程状态”右上角的脚注哦)
答案:子进程已经退出,但是父进程退出时并不读取该子进程的状态,使得父进程结束后子进程仍然保持等待父进程来检查其退出状态的状态,但是父进程已经终止了,所以该子进程的Z状态将会一直存在,这个时候谁都拿它没办法,因为子进程已经结束了,就算使用
kill -9 PID
2这种发送终止信号的命令都无效
我将介绍进程相关的常用的三个信号
kill -9 PID:终止进程 kill -19 PID:暂停进程(进程会变为T状态,即暂停或调试状态) kill -18 PID:继续运行(进程会变为R状态或者R+状态,R和R+的区别是: R:在后端运行,不会占用命令行,前端照样进行命令行解释,按
ctrl + c
并不会终止程序,要输入kill -9 PID才可终止 R+:在前台运行,这种会占用命令行,当进程在前台运行时,你在命令行中输入ls这种命令将不会被响应,因为命令行解释器已经被进程占用了,可用ctrl + c
终止)
答案:造成内存泄漏
解释:
在上一个僵尸进程的形成原因
中脑子不好的小菜鸟已经指出:子进程的Z状态将会一直存在,这个时候谁都拿它没办法。
但是进程存在会占用内存资源,但是
这就导致了这块内存谁也用不了,也就是浪费了,就造成了内存泄漏
答案:使用wait或者waitpid函数
在Linux中怎么查函数的手册呢?
即答:百度
输入:man [选项] 函数名
我们先输入:man 2 wait
【注】: man wait:这种man直接加要查的内容的方式查找的是shell命令 man 2 wait:这种man加2加要查的内容的方式查找的是手册内容
我们将看见如下部分
NAME
wait, waitpid, waitid - wait for process to change state
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
剖析一下这个部分:
NAME
wait, waitpid, waitid - wait for process to change state
表示这个函数时用来等待进程的状态改变的
#include <sys/types.h>
#include <sys/wait.h>
系统库函数
pid_t wait(int *status);
当我们在手册页输入:/return val
时3,我们将看见如下部分
wait(): on success, returns the process ID of the terminated child; on error, -1 is returned.
这里表示的是:
答案:所以当我们用wait这个函数时,当子进程的状态由R或R+状态(运行状态)变为Z状态(僵尸状态)时,wait就会读取到,并发送给父进程------->这就实现了父进程读取了子进程的退出状态------>子进程可以被释放------>Z状态消失,内存归还------>解决了内存泄漏问题
在这个部分,我会用代码演示父进程怎么获取子进程的退出信息,如下是演示代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdlib.h>
int main()
{
pid_t id = fork();//创建子进程
if (id == 0)//子进程
{
int cnt = 5;
while (cnt)
{
printf("I am child,pid = %d\n", getpid());
cnt--;
}
exit(0);//正常退出
}
else if(id > 0)//父进程
{
sleep(7);
int status = 0;
pid_t ret = waitpid(id, &status, 0);
if (ret > 0)
{
printf("等待子进程成功,ret = %d,子进程的退出信号:%d,子进程的退出代码:%d\n", ret, (status & 0x7f), (status >> 8) & 0xff);
}
}
else//创建失败
{
perror("fork");//头文件:<stdio.h>
exit(1);//0:正常结束 非0:异常结束 头文件:<stdlib.h>
}
return 0;
}
同样,我们输入:man 2 waitpid
我们将看见如下部分:
NAME
wait, waitpid, waitid - wait for process to change state
SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
pid_t waitpid(pid_t pid, int *status, int options);
如果我们用了演示代码,并且同时观察了该进程的状态(我们可以在复制后的窗口输入如下代码来时隔一秒的速度观察进程的状态: while : ; do ps axj | head -1 && ps axj | grep 你的可执行程序名 | grep -v grep; sleep 1;echo "-----------------------------------"; done
),我们将发现如下情况:
当再过两秒后,我们会发现Z状态消失,只留下父进程------->这就实现了对僵尸进程的处理
而我们如何知道子进程的退出码和退出信号呢
我们的演示代码中就有这个片段:
int status = 0;
pid_t ret = waitpid(id, &status, 0);
if (ret > 0)
{
printf("等待子进程成功,ret = %d,子进程的退出信号:%d,子进程的退出代码:%d\n", ret, (status & 0x7f), (status >> 8) & 0xf0);
}
聪明的你可能会好奇,为啥有下面这两个东西
讲到这里我就要和你讲讲waitpid函数给status赋的值是怎么得到的了
1111
,所以当写为0xff时,就是1111 1111
)kill -9 PID
杀死)
低7位为终止信号,注意这里的是7位,和上面的不同
0111
这样子我们就能通过status得到子进程的退出状态[5]和终止信号[6]啦
关于退出状态和终止信号:
kill -l
**来知道该信号是因为什么原因而退出的了core dump标志
,这是gdb调试崩溃程序信号,由于脑子不好的小菜鸟还没学到(>人<;),所以暂时没有提到,各位自行查阅ps axj | head -1 && ps axj | grep "你的进程名"
,其中STAT那一列就是进程状态啦 ↩︎
kill -l
,就可以看见所有的信号代表的含义了啦 ↩︎
/
+ 你要查找的内容
时,可以在文档中查找你要查找的相关信息 ↩︎