进程的基本概念:
程序的一个执行实例 ,正在执行的程序等等 ——— 课本概念担当分配系统资源的实体,例如cpu时间,内存 -----内核的观点
一、进程的管理
processbar 存储在磁盘中的可执行文件 可执行文件在启动/运行的同时,会将 往 内存中加载 / 传输 代码和数据,这一段代码和数据是代表进程的代码和数据,但并不是进程,至少进程对应的数据和代码
于此同时,为了调用和管理进程,cpu会使用一种名叫PCB的结构体,通过该结构体内部的内存指针,指向内存,顺着内存找到可执行文件传输入内存中的进程相对数据和代码
PCB结构体在内存的内的排列方式类似与数据结构中的链表,因此cpu对进程的调用和管理就变成了对多个PCB结构体组成的链表的增删查改
为什么要有PCB呢?(OS是操作系统、PCB又叫进度控制块)
- PCB是OS中最重要的记录型数据结构,它扮演着记录进程信息、描述进程状态以及控制进程运行的关键角色。 PCB中记录了OS所需的、用于描述进程情况及控制进程运行所需的全部信息。
- 同时PCB是为了让OS方便对进程进行管理
因此,便可以得出一个结论,进程 = PCB + 可执行程序的代码 + 可执行程序的数据
- 同时,结构体PCB 在LInux 内部的具体名称叫做 task_struct 结构体,在这个结构体的内部存储的是Liux进程控制块,用来帮助用户对进程进行调控
- 而,对进程的调控,本质就是在对Linux进程控制块在内存中进行排队,就是让结构体task_struct在内存中进行排队
如何理解进程的动态运行?
根据内存中PCB结构体的数据结构,可以得到只要我们的进程结构体PCB(task_struct)在不同的队列中进行运行,就可以得到和访问不同的资源!这需要对进程控制块进行调度运行。
./XXXX 在Linux中,该代码就是启动或者运行可执行程序,它的本质是让系统创建进程并且运行进程!同时,在linux中的大部分可执行操作和命令,它们的本质也是运行进程!
进程的pid属性
pid,进程id, pid是一种进度标识,在由于内存的内部有多个PCB结构体/进程控制块,为了区分这些进度块,从而衍生出pid,是每一个进程都有的唯一标识。
同时,和pid 相对因的是ppid 也就是父进程,每一个进程都是由父进程创建的,子进程可以继承父进程的代码,而父进程的代码和数据一般来自于磁盘、
在Linux中,可以创建C语言文件,使用函数getpid()和函数getppid()获取当前进程的pid和ppid
进程的创建
进程可以通过fork()函数,进行创建,同时之后的新进程就由fork()创造的进程产生,是它的子进程,而子进程和父进程的代码共享,但是数据分别独立,这也表明了进程的特点,独立性!
查看进程:
使用ps aux或者ps ajx 进行所有进程的查看,使用| grep 关键字 查找需要查看的进程,因为grep本身也会产生包含关键字的进程,使用| grep -v grep进行屏蔽操作!
查看进程信息使用 /proc , 如:要获取PID为1的进程信息,你需要查看 /proc/1 这个文件夹
以下代码是查看所有进程的信息
Linux的进程状态:
S状态:
S是休眠状态!S状态验证如下:
printf是在显示器上打印东西,而根据冯诺依曼体系,prinftf是先往cpu和内存打印东西,但是cpu的处理的速度比屏幕显示代码以及内部的传输到cpu的速度要快,所以cpu大部分时间都在等待数据的输入,并没有都在运行,而且运行的熟读极快造成了速度差,所以被判断是休眠状态
所以会造成代码刷屏时,会处于休眠状态,其实休眠状态就是cpu处于等待状态,也可以说,休眠状态就是进程在等待资源的就绪
同时休眠状态也叫做可中断状态,可以通过ctrl+c进行中断!
最后如上面代码中的休眠状态 S + 中的+表示在前台运行, 可以在启动可执行文件时使用 &把进程移到后台运行
同时如果进程在后台运行,那么并不能使用ctrl +c 对进程进行中断,需要使用 kill-9 进程的pid 对进程进行中断
R状态:
R状态验证如下:R表示是进程运行的状态!
T状态和t状态:
T 和 t 状态,都是让进程处于暂停的状态!而且暂停都是外部使用指令对进程进行暂停
暂停也叫做等待被进一步唤醒!
验证:
使用另一个进程控制目标进程!
使用 kill - l 代码 查看进程信号 只需要知道前31个即可 这些进程型号都是和宏一样
其中 使用 kill -19 进程的pid 进行进程的暂停:
还可以使用 kill -18 进程的pid 让进程继续运行!
同时进程的暂停也可以使用调式中的打断点进行暂停,也就打断点就是通过暂停实现的!
而断点的暂停其实就是t,t表示当前的进程遇到了断点处 被暂停了!
D状态:
D状态是Linux系统中比较特有的一种状态,是对磁盘的一种特殊的状态! disk sleep disk是磁盘的意思
验证举例:
当我们讲进程的一部分数据传输到磁盘中,这个过程根据冯诺依曼体系可以变为,是把对应的数据传给外设的过程
而当进程把数据传给磁盘进行数据存储的过程中,进程会进入一种状态,这个状态就是休眠状态,
此时的进程在等待数据完全传入磁盘中
当内存不足时,Linux有权利杀死进程,释放空间!当然这个的前提条件是内存严重不足,系统压力非常大!
而当内存严重不足且 进程进行数据传输至磁盘是,磁盘会写入失败,数据会丢失,因为进程没了!
所以为了防止,操作系统删除 这种 在传输数据的进程,就出现了一个新的状态 D状态,D状态表示在传输数据,不可被操作系统杀死,D状态又叫做深度睡眠,不可中断睡眠
僵尸状态:
一个Linux的进程退出的时候,进程的退出,进程的退出是要将自己的信息保留在属于它的PCB当中,如果没有人读取它的PCB中的进程消息,那么该进程内部的内容就一直不释放。
进程的退出一般是将它的代码和数据进行释放,而它的PCB内容和数据结构则不会释放
直到将来对进程等待,如果不等待进程,那么进程就会变成僵尸状态,如果读取了等待了,那么进程则会将它的内容也就说PCB的数据结构进行释放
进程在退出后会处于僵尸状态,需要父进程进行回收,如果不回收那么进程就一直会处于僵尸状态
验证:
创建子进程,子进程循环五次就退出
而else内部是父进程,这里证明了父进程一直什么都没做,当子进程退出后会一直进入僵尸状态!等待被回收!
之后子进程进入了僵尸状态,并且出现了defuct 这个是表示僵尸进程的标志之一
僵尸进程表示的是一斤运行完毕,但是要维持自己的退出星系,在自己的进程PCB中会记录自己的退出信息,让未来的父进程进行读取
如果不让父进程进行读取,那么僵尸进程会一直存在!
因为进程已经运行完毕,但是进程 = 内核数据结构PCB + 进程的代码 + 进程的数据
而当僵尸进程一直存在,那么会占用一定的内存空间,要是不释放会一直存在,这种可能会造成内存泄露问题!
而且如果我们释放PCB也就释放僵尸进程,释放是由操作系统操作的,而读取PCB内部数据是由父进程进行的
同时我们可以使用waitpid命令进行释放,当僵尸进程被释放后,该进程的状态就会变成X状态!也就是进程死亡!
为什么进程要等待,因为我们要读取进程的信息!
孤儿状态:
就是该进程在运行期间,这个进程的父进程先退出了,那么这个进程就是孤儿进程!
在这个代码中,fork建立子进程,让子进程一直运行,同时让父进程率先结束!
可以看到父进程ppid变成了1
同时我们需要注意,之前的僵尸进程中,父进程是需要读取变成僵尸进程的子进程内部的内容
但是这里父进程先退了,那子进程之后变成僵尸进程后该怎么办呢?
就在这时我们就可以看到上面信息中dppid父进程变成了1,也就是说子进程之后退出后的信息由1号进程进行回收!
一号进程可以表示为OS也就说操作系统本身!
那孤儿进程为什么要被1号进程回收?因为我们要保证子进程正常的被回收!
为什么不需要关注僵尸进程和内存泄露嗯?或者说,为什么为什么我们启动了所有的进程(inux的命令也是进程),但是我们不关注僵尸进程和内存泄露呢?
因为会有bash进行回收新进程的PCB