关于进程状态

目录

进程的各种状态

运行状态

阻塞状态

挂起状态

linux中的进程状态、

进程状态查看

S状态(浅睡眠)

[t 状态(追踪状态)](#t 状态(追踪状态))

T状态(暂停状态)

​编辑

kill命令手册

D状态(深度睡眠)

Z状态(僵尸状态)

孤儿状态


我们知道cpu是通过一个调度队列来处理调度一个个进程的,一个cpu,一个调度队列!

一个个进程肯定有多种不同的状态,到底是执行完了还是没有,或者是一直执行某个语句不动的状态,所以我们现在详细讲讲。

进程的各种状态

运行状态

运行状态比较好理解,我们说只要进程在调度队列中就都是运行状态(running)。

为什么同一个节点可以在不同的数据结构中呢?怎么实现的?

我们之前在学习数据结构的时候,同一个节点只能在一个数据结构中,而OS中却不是这样的,它可以在不同的数据结构中。

有了list_head,我们只需要管理list_head就能间接管理进程pcb。

我们可以在task_struct 中设计多个list_head结构体,这样多个数据结构容器只需要对各自的list_head结构体管理就能间接管理task_struct:

阻塞状态

阻塞状态:等待某种设备(键盘,显示器,网卡,磁盘,摄像头......)或者资源的就绪。

我们最常接触到的阻塞就是程序运行在scanf语句的时候,等待键盘的输入,说白了就是在等待键盘就绪,这时候进程从运行状态变为阻塞状态。

更深理解:

我们知道OS管理硬件也是和进程一样一个个结构体描述硬件,在每一个硬件中其实也有一个队列,叫等待队列。程序刚开始在运行的时候是运行状态,在执行到sacnf语句时,这个过程,进程pcb从调度队列链出,链入键盘的等待队列。此时进程就是阻塞状态。

当我们输入完毕,键盘就绪,OS判断等待队列是否为空,不为空将这个进程pcb就会重新链出等待队列,链入调度队列,变为运行状态。

设备管理:

挂起状态

磁盘中有一个swap交换分区(大小是内存的1.5倍或2倍等),当内存资源严重不足的情况下,OS将阻塞进程的代码和数据唤入swap交换分区,此时这些进程状态就叫阻塞挂起状态。当这些进程要被调度时,将这些进程的代码和数据再唤入内存中。有时甚至会将调度队列中的末尾进程唤入swap交换分区。

图:

linux中的进程状态、

进程状态查看

复制代码
 ps aux / ps axj  命令
  • a:显⽰⼀个终端所有的进程,包括其他⽤⼾的进程。
  • x:显⽰没有控制终端的进程,例如后台运⾏的守护进程。
  • j:显⽰进程归属的进程组ID、会话ID、⽗进程ID,以及与作业控制相关的信息
  • u:以⽤⼾为中⼼的格式显⽰进程信息,提供进程的详细信息,如⽤⼾、CPU和内存使⽤情况等

在linux内核中,linux状态和以上的状态有所不同,上面只是适合所有操作系统,但是不同操作系统之间还是有差别的。

在每个task_struct中都有一个变量记录一下进程的状态,上图是一个状态数组,而一般task_struct中的这个变量其实就是一个整数(每个不同的整数代表不同的状态)。

  • R ----运行状态
  • S ----浅睡眠状态(可中断睡眠状态)
  • D ----深睡眠状态(不可中断睡眠状态)
  • S和D其实都属阻塞状态
  • t ----追踪状态
  • T ----暂停状态
  • X ----死亡状态
  • Z----僵尸状态

我们看看具体概念:

  • R运⾏状态(running):并不意味着进程⼀定在运⾏中,它表明进程要么是在运⾏中要么在运⾏ 队列⾥。
  • S睡眠状态(sleeping):意味着进程在等待事件完成(这⾥的睡眠有时候也叫做可中断睡眠 (interruptible sleep))。
  • D磁盘休眠状态(Disksleep)有时候也叫不可中断睡眠状态(uninterruptiblesleep),在这个 状态的进程通常会等待IO的结束。
  • T停⽌状态(stopped):可以通过发送SIGSTOP信号给进程来停⽌(T)进程。这个被暂停的 进程可以通过发送SIGCONT信号让进程继续运⾏。
  • X死亡状态(dead):这个状态只是⼀个返回状态,你不会在任务列表⾥看到这个状态。

我们一个个来讲解!!!

S状态(浅睡眠)

我们可以换成后台输入运行,此时我们的命令行可以继续输入其他命令:

t 状态(追踪状态)

当一个程序被debug的时候,就是一个追踪状态。

T状态(暂停状态)

kill命令手册

kill有很多命令,我们可以查:

其中:

  • -9 :杀掉进程
  • -18:恢复进程
  • -19:暂停进程

D状态(深度睡眠)

首先为什么要有D状态呢?

看一个情景:

某个进程,要将100MB数据写入磁盘,此时进程状态是S状态(等待数据全部写入磁盘,写完之后会告诉进程成功与否(返回值实现)),如果此时内存空间严重不足,我们知道OS会将一些阻塞进程甚至调度队列末尾进程挂起,可是这样仍然不足呢?那么OS很有可能将这个写入磁盘进程杀掉,这个进程杀掉了,那这100MB数据怎么办?如果写入磁盘时,磁盘空间也不足,写入失败了,本来要返回告诉这个进程失败信息,但是此时进程被杀掉了,也就是说现在用户也不知道这100MB数据写入失败了,这100MB数据就丢失了!如果这100MB数据是某个银行转账一天的流水呢!

所有说才会有D状态进程,不可被OS杀掉,这样就算写入失败了,用户也知道失败了!

一般在高IO流的时候才会出现!

Z状态(僵尸状态)

只要是进程,那么它一定有父进程,而当子进程运行结束,子进程的相关信息是需要被父进程获取的,而我们知道进程的相关信息是在它的pcb的,也就是说子进程运行完,此时OS可以将它的代码和数据释放掉,但是pcb不能释放掉,父进程获取完子进程信息之后,子进程正式退出!

子进程运行完之后,父进程获取子进程相关信息,子进程正式退出之前,这就是僵尸状态!

看代码:

看现象:

如果父进程一直不管,一直不回收子进程的pcb,那么子进程一直都是僵尸状态,子进程的pcb一直就得不到释放,这会导致内存泄露。

那进程内存泄露了,进程退出了,内存泄露还存不存在?

不存在。

就像之前我们学习c语言的时候,一个main函数里面,死循环开辟内存,而不释放,就会内存泄漏,而当程序结束完(return 0后),OS就自行回收内存!

那什么样的进程害怕内存泄漏呢?

我们刚刚说的那个显然是不害怕内存泄漏的,一些常驻内存的进程就会害怕内存泄漏。

常驻内存的进程就是那些启动之后不退出的,一旦启动不退出的进程。

比如操作系统就是一个启动不退出的进程,如果操作系统内核代码出现了内存泄漏,就会越来越卡。

task_struct的节点是怎么申请和释放的?

在平常的使用当中,大部分都是多进程并发的,那肯定离不开一个个的pcb去不断申请和释放,但却不是我们常认识的那种申请和释放。

有一个unuse区域,专门存储那些要释放的task_struct节点,当我们要释放某个task_struct的时候,将这个节点放入unuse区域即可,当我们要申请一个新的节点的时候,我们只需要在unuse区域中拿即可!

孤儿状态

父子进程关系中,如果父进程先退出,子进程要被1号进程领养,这个子进程就叫作孤儿进程。

这1号进程其实就是操作系统!既然被1号进程领养自然要被1号进程回收!

看代码:

现象:

子进程被领养之后就变成后台进程了!

看看1号进程:

我们可以看到,这个1号进程是叫systemd(老版本叫init)进程,它其实也有一个0号进程,但我们一开机这个0号进程就被1号进程取代了,这个我们不详细谈。

为什么1号进程需要领养呢?

前面知道,子进程需要被父进程获取信息(回收),这个时候子进程是僵尸状态,但是此时子进程没有父进程了,那么这个子进程就会内存泄漏,所以需要被领养,最后统一回收!

好了,我们下期见!

相关推荐
爱莉希雅&&&2 分钟前
Linux中服务器时间同步
linux·运维·服务器
廖圣平2 分钟前
linux删除大文件日志后之后,df -h还占内存
linux·运维·服务器
凤山老林2 分钟前
JVM 系列:JVM 内存结构深度解析
java·服务器·jvm·后端
飘若随风3 分钟前
Linux教程-常用命令系列二
linux
保证四个小时充足睡眠1 小时前
【并行分布计算】Hadoop伪分布搭建
linux
ZaaaaacK1 小时前
守护进程编程
linux·运维·网络
晓龙的Coding之路1 小时前
python生成项目依赖文件requirements.txt
linux·开发语言·python
gblfy2 小时前
DeepSeek + Dify + Ollama + Docker + Linux 私有化部署,构建你的专属私人 AI 助手
linux·docker·dify·本地部署·ollama·deepseek·私有化
萌萌哒草头将军2 小时前
注意!⚠️ 🔥 🚧 PostgreSQL 存在安全漏洞,请及时更新版本或者停用删除相关服务,防止中招!🚀🚀🚀
服务器·postgresql·xss
曼岛_2 小时前
[密码学基础]GMT 0029-2014签名验签服务器技术规范深度解析
运维·服务器·密码学·签名验签服务器