我们知道进程有多个
假设现在只有一个一个CPU,那进程会去争抢cpu的资源。
这个时候cpu会有一个运行队列,来实现让进程按照顺序执行。
这个是进程的运行队列,一个个进程都加载进运行队列中。
这个时候对应进程的代码和数据都加载进了进程之中
所以说内存不光要维护PCB,同时还管理着程序的代码和数据。
在运行队列中的进程就是运行态
因为进程未被内存读取前是在磁盘中的程序,所以对进程的管理实际上是操作系统对软件的管理
如果进程需要访问硬件(设备)中的资源,这个时候就要涉及到操作系统对进程的管理。
操作系统管理硬件也是先描述再组织,对硬件也会进行描述,硬件中有等待队列。
每个设备都有个等待队列
比如说一个进程需要键盘进行输入,操作系统就会让该进程进入到该设备等待队列。
在设备的等待队列中的进程就叫阻塞态
比如说C语言的scanf函数等待输入时,这个时候就是阻塞状态
我们要注意,当进程处于阻塞态中
进程的自身代码和数据还是存在内存中。
如果这时候进程在阻塞态中等待设备资源就位时
突然操作系统内部的内存资源不足了。
操作系统就会在进程中进行检查
将一些在挂起态的进程的pcb保留,将内存中的代码和数据从内存中丢弃
当进程所需的设备资源就位时,再将数据和代码从磁盘中重新读取
上面的操作系统中的进程状态我们只是随便提一下而已。
这里用grep进行测试。
这里我们能发现test处于R+的运行状态。
这里的+先不谈,之后的博客中会进行讲解。
这里的S的睡眠状态,可以看成是操作系统中的阻塞状态。
这里我们能发现进程一直处于设备资源的到位,处于S的阻塞状态。
前面我们在操作系统进程的挂起态中我们提到:
当内存太满的时候,系统有可能,会自己干掉进程
但是如果遇到一个进程正在向磁盘写入数据,正好被干掉的话,就会导致数据的丢失。
如果正好是比较重要的数据,那这个后果是不能承受的
所以创建了一个深度睡眠模式
专门交给那些向磁盘写入数据的进程。
防止系统误杀进程,从而造成数据丢失。
这个状态可以看作是程序处于设备等待队列的阻塞状态。
只不过这个阻塞状态不光是系统控制的,我们用户可以进行停止和继续。
这里就比如说gbd调试
我们打了断点后进程运行到断点处,就会进入stop状态
就会发现这里的进程处于:
gdb test会等待指令进行下一步的阻塞态
而test处于t状态
终止状态 :在相关进程丢尽垃圾队列中等待释放。
当子进程死了以后,不会立马进行释放,而是会保留子进程的PCB以及内存和资源,让关心子进程的进程或者父进程来检查。
确定了子进程的结束原因以后,之后再在放入终止状态。
这个保留PCB和内存资源的状态,就叫僵尸状态
这里可以来测试一下
这里我们用fork函数,让子进程消失,让父进程保留。
所以如果僵尸进程处理不当就会引起内存泄漏:
进程一般退出的时候,如果父进程没有主动回收子进程的信息。
子进程会一直让自己处于Z状态,进程相关资源尤其是task_struct不会被释放。
僵尸进程会一直占用内存资源(内存泄漏)。
就比如我们上面的测试代码,这个时候子程序会一直处于僵尸状态。
至于如何处理,这个就留到之后的博客了
父子进程,父进程先退出,子进程的父进程会被改成1号进程(操作系统),相当于被系统给领养
这里可以来测试一下:
这里我们让父进程先走,然后不停打印子进程的父进程pid
这里我们就能发现父进程从3090变成了1
这里就看出子进程被操作系统给收养了。
为什么要领养:
因为子系统进入Z状态的话,这样就没有人来收尸了。