Linux 僵尸进程和孤儿进程, 进程优先级
僵尸进程
之间在进程状态中了解到了 "僵尸状态".
那么处于僵尸状态的进程就是僵尸进程.
僵尸状态是一种特殊的进程状态, 它表示一个进程已经完成执行, 但其父进程尚未回收其终止状态.
"僵尸状态" 的本质就是死亡状态.
如何理解僵尸进程:
举个例子: 一个正常的人突然死亡了, 我们并不会直接将人送入火葬场, 而是要确认这个人的死亡原因.这个人的死因是什么, 自杀, 意外, 还是他杀. 我们需要进行调查. 进程也是如此, 当一个进程死亡后, 我们也需要知道, 进程的死因 (任务已完成, 程序出现错误 ...). 在原因未查明之前, 这个 "尸体" 会被保留. 此时就处于僵尸状态.
创建一个进程就是为了完成任务, 现在进程结束了, 那么任务完成的怎么样, 还需要通过一些信息来了解.
int main()
{
// return 1;
return 0;
}
在 C/C++ 程序结束时, 一般都会有一个返回值. 这个返回值就是一种信息, 可以用来表示任务完成的怎么样.
如: 返回 0, 表示程序正常执行结束, 返回 1 表示出现了错误.
所以在父进程还没有接收到这个返回信息时, 子进程就会一直处于僵尸状态, 这样就形成了僵尸进程.
当一个进程结束时, 进程的结束信息会被保留在这个进程的 PCB 中,
进程的代码和数据等资源都会被回收, 但 PCB 不hi立即释放,
直到 父进程 读取了 PCB 中的结束信息之后, PCB 才会被释放.
当一个进程长期处于 Z 状态, 没有被及时回收, 那么就有内存泄漏的风险.
#include <stdio.h>
#include <unistd.h>
int main()
{
int id=fork();
if(id==0)
{
sleep(1);
printf("child: %d\n", getpid());
exit(2);
}
if(id>0)
{
printf("parent: %d\n", getpid());
while(1)
{}
}
return 0;
}
可以观察到, PID 为 2180110 的进程的父进程是, PID = 2180109.
我们看到了子进程已经退出了, 父进程一直在运行, 但没有接收子进程退出信息.
所以子进程一直处于 Z "僵尸状态".
孤儿进程
顾名思义, 就是这个进程没有了自己的父进程.
当一个子进程的父进程, 在子进程推出之前, 先一步退出了, 那么这个子进程就变成了 "孤儿进程".
当一个进程没有父进程, 那么也就没有进程会为它收尸 (读取PCB中的退出信息), 那么就会造成僵尸进程, 如果长期不回收资源, 就会一直暂用操作系统的资源, 最终就有可能导致内存不足, 操作系统崩溃.
为了避免孤儿进程退出后, 一直处于僵尸状态,
操作系统会为这个孤儿进程安排一个 "义父",
当这个孤儿进程结束后, 就由这个义父来回收
可以看到, 这个孤儿进程被安排的义父就是 PID = 1 的进程.
PID = 1 的这个进程就是操作系统本身.
进程优先级
进程优先级: 是一个用于确定进程执行顺序的数值, 它影响进程获得 CPU 时间片的频率.
使用命令查看进程优先级:
ps -l 或者 ps -al
需要关注的值有两个
- PRI: 进程优先级标识符, 这个值越小, 进程优先级就越高
- NI: 优先级的修正数 (nice 值)
在 Linux 中, 进程的默认优先级都是80,
进程优先级的取值返回: 60 ~ 99,
进程优先级 PRI = 80 - NI.
使用 ps 打印出来的 PRI = 80 - NI.
即: ps 命令打印出来的 PRI 是经过计算后得到的实际的 PRI.
进程优先级一般是不会去随意修改的.
操作系统调度进程时, 需要较为均衡的让每个进程都得到调度.
如果随意的修改进程的优先级, 就有可能导致, 某个进程调度次数变多,
而某个进程优先级太低, 迟迟得不到调度.
这样就会造成 "进程饥饿"