僵尸进程与孤儿进程

1、进程

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体。它不只是程序的代码,还包括当前的活动,通过程序计数器的值和处理寄存器的内容来表示。通俗点讲,进程是一段程序的执行过程,是个动态概念。

程序运行必须加载在内存中,当有过多的就绪态或阻塞态进程在内存中没有运行,因为内存很小,有可能不足。系统需要把他们移动到内存外磁盘中,称为挂起状态。就绪状态的进程挂起就是挂起就绪状态,阻塞进程挂起就称为阻塞挂起状态。

每个进程的产生都有自己的唯一的ID号(pid),并且附带有一个它父进程的ID号(ppid)。进程死亡时,ID被回收。

进程间靠优先级获得CPU资源,时间片段轮换来更新优先级,以保证不会一个进程占据CPU时间过长。每个进程都得到轮换运行,因为这个时间非常短,所以给我们的感觉就好像是系统在同时运行好多进程。
 

2、僵尸进程

产生原因:子进程先于父进程退出,他要保留退出原因在pcd中,因此退出后不会自动释放所有资源,子进程退出后操作系统会通知父进程这个家属说子进程退出了,你去获取一下原因,然后完全释放子进程资源。假如父进程不管子进程的退出状态,那么这个子进程将进入僵尸状态,成为僵尸进程。

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/types.h>
 
int main()
{
	pid_t pid=fork();
 
	if(pid==0)  //子进程
	{
     	printf("child id is %d\n",getpid());
		printf("parent id is %d\n",getppid());
	}
	else  //父进程不退出,使子进程成为僵尸进程
	{
        while(1)
		{}
	}
	exit(0);
}

一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在Linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。这个僵尸进程需要它的父进程来为它收尸,如果他的父进程没有处理这个僵尸进程的措施,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。

试想一下,如果有大量的僵尸进程驻在系统之中,必然消耗大量的系统资源。但是系统资源是有限的,因此当僵尸进程达到一定数目时,系统因缺乏资源而导致奔溃。所以在实际编程中,避免和防范僵尸进程的产生显得尤为重要。

危害:资源泄露

解决方式:

任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“defunct”。如果父进程能及时处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。所以孤儿进程不会占资源,僵尸进程会占用资源危害系统。我们应当避免僵尸进程的出现。

1):一种比较暴力的做法是将其父进程杀死,那么它的子进程,即僵尸进程会变成孤儿进程,由系统来回收。但是这种做法在大多数情况下都是不可取的,如父进程是一个服务器程序,如果为了回收其子进程的资源,而杀死服务器程序,那么将导致整个服务器崩溃,得不偿失。显然这种回收进程的方式是不可取的,但其也有一定的存在意义。

2):SIGCHLD信号处理

我们都知道wait函数是用来处理僵尸进程的,但是进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。

如果创建了5个子进程,但是销毁的时候仍然有两个仍是僵尸进程,这又是为什么呢?

这是因为当5个进程同时终止的时候,内核都会向父进程发送SIGCHLD信号,而父进程此时有可能仍然处于信号处理的deal_child函数中,那么在处理完之前,中间接收到的SIGCHLD信号就会丢失,内核并没有使用队列等方式来存储同一种信号

所以为了解决这一问题,我们需要调用waitpid函数来清理子进程。

3.孤儿进程

一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

子进程死亡需要父进程来处理,那么意味着正常的进程应该是子进程先于父进程死亡。当父进程先于子进程死亡时,子进程死亡时没父进程处理,这个死亡的子进程就是孤儿进程。

但孤儿进程与僵尸进程不同的是,由于父进程已经死亡,系统会帮助父进程回收处理孤儿进程。所以孤儿进程实际上是不占用资源的,因为它终究是被系统回收了。不会像僵尸进程那样占用ID,损害运行系统。
 

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/types.h>
 
int main()
{
	pid_t pid=fork();
 
	if(pid==0)
	{
		printf("child ppid is %d\n",getppid());
		sleep(10);     //为了让父进程先结束
		printf("child ppid is %d\n",getppid());
	}
	else
	{
		printf("parent id is %d\n",getpid());
	}
 
	exit(0);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值