进程优先级调度
什么是进程优先级调度?
简单说,OS 会给每个进程分配一个 "优先级数值",调度器每次选 CPU 时,优先挑优先级最高的就绪进程运行。比如我们电脑里的杀毒软件后台扫描(低优先级),不会打断正在打字的编辑器(中优先级);而系统的内存管理进程(高优先级),哪怕编辑器在运行,也能优先占用 CPU 处理关键任务 ------ 这就是优先级调度的核心目的:资源向核心任务倾斜,平衡 "响应速度" 和 "资源利用率"
动态、静态优先级是什么?
-
静态优先级:进程创建时就定好,后续基本不变(比如程序员通过
nice命令设置,或系统默认分配)。比如 Linux 里nice值范围是-20~19,值越小,优先级越高-------20 是最高,19 是最低 -
动态优先级:进程运行中,OS 根据行为动态调整。比如:
-
IO 密集型进程(比如浏览器、数据库,经常等磁盘 / 网络):OS 会提高优先级,因为它 "占着 CPU 的时间短",多给机会能让用户感觉更流畅;
-
CPU 密集型进程(比如视频渲染、数学计算,一直占 CPU):OS 会降低优先级,避免它独占 CPU,导致其他进程卡壳。
-
什么是两种调度策略?
-
抢占式:高优先级进程就绪后,能直接 "打断" 正在运行的低优先级进程,抢占 CPU。比如你正在用播放器(中优先级),突然系统弹出杀毒提醒(高优先级)------ 播放器会暂时暂停,让提醒先显示,这就是抢占式的好处:关键任务响应快。
-
非抢占式:低优先级进程没跑完之前,高优先级进程只能等着,不能打断。现在很少用,缺点很明显:如果低优先级进程卡死,高优先级进程也没法运行。
什么时候换进程?
-
进程主动放弃 CPU(比如调用
sleep、等待 IO 完成); -
进程时间片用完(哪怕优先级高,也不能一直占着,比如 Linux 里高优先级进程时间片更长,但还是会轮换);
-
新的高优先级进程就绪(比如刚创建的系统进程,或之前等待 IO 的高优先级进程完成等待);
-
发生中断(比如键盘输入、网络数据到达)
常见的调度器
一、O(N)调度器
what?
这是最早期的调度器,它通过遍历整个就绪队列来寻找优先级最高的进程,时间复杂度是 O (N)
1、核心
-
系统维护一个按优先级排序的链表数组,每个优先级对应一个链表。
-
调度时,从最高优先级开始,逐个遍历链表,找到第一个可运行的进程。
-
进程运行时,会消耗时间片,时间片用完后被移到低优先级队列或重新计算优先级
2、特点
-
优点:实现简单,逻辑直观。
-
缺点:
-
当就绪进程数量多时,遍历开销大,调度延迟高(比如几百个进程时,遍历要花不少时间)。
-
高优先级进程可能长期霸占 CPU,导致低优先级进程 "饥饿"
-
二、O(1)调度器
what?
为解决 O (N) 的遍历开销而生,调度决策的时间复杂度是 O (1),不随就绪进程数量变化
1、核心
-
双数组结构:
-
active数组:存放当前有时间片的进程,按优先级分组。 -
expired数组:存放时间片用完的进程。
-
-
位图索引:用一个位图(bitmask)记录哪些优先级有可运行进程,调度时通过位图快速定位最高优先级(位运算直接找第一个置1的位)。
-
时间片分配 :高优先级进程时间片长,低优先级短,用完后移到
expired数组,当active为空时,交换两个数组
2、特点
-
优点:调度速度快,无论多少进程,找最高优先级进程都是 O (1) 操作。
-
缺点:
-
对交互式进程优化不足(比如 IO 密集型进程可能因时间片用完被打入低优先级)。
-
优先级数量有限(比如 256 个),灵活性不够
-
三、时钟中断
what?
调度器的 "触发器",通过硬件时钟定期触发调度,保证系统公平性和及时性
1、核心
-
硬件时钟每 10ms ~ 100ms 产生一次中断(时钟节拍)。
-
中断发生时,内核会:
-
更新系统时间。
-
减少当前进程的时间片,时间片为 0 时标记为 "需要重新调度"。
-
检查是否有更高优先级进程就绪,若有则触发抢占。
-
定期进行负载均衡(比如把进程从繁忙 CPU 移到空闲 CPU)
-
2、作用
-
避免进程无限占用 CPU,保证时间片轮转。
-
及时响应高优先级进程,实现抢占式调度。
-
维护系统时间和进程运行统计信息
四、CFS(完全公平调度器)
what?
目前 Linux 默认调度器,基于 "完全公平" 思想,用虚拟运行时间(vruntime) 替代固定时间片,时间复杂度 O (logN)
1、核心
-
vruntime :进程的 "虚拟运行时间",计算公式为
实际运行时间 × (1024 / 进程权重)。优先级越高,权重越大,vruntime 增长越慢。 -
红黑树:所有就绪进程按 vruntime 排序存入红黑树,调度时取树中 vruntime 最小的进程(最 "饥饿" 的进程)。
-
时间片动态调整:没有固定时间片,进程运行一段时间后,若 vruntime 超过其他进程,会被抢占。
-
交互式优化:IO 密集型进程(如键盘输入、鼠标操作)因经常睡眠,vruntime 增长慢,会被优先调度,保证响应速度
2、特点
- 公平性好,每个进程获得的 CPU 时间与优先级成正比。
-
对交互式进程友好,响应速度快。
-
支持动态优先级调整,适应不同负载场景
五、总结
O (N)(简单但低效)→ O (1)(高效但不够灵活)→ CFS(公平且灵活) ,而时钟中断调度是所有调度器的基础触发机制
早期 Linux 用 O (N) 调度,遍历队列找进程,简单但进程多了就卡;后来升级到 O (1),用位图快速定位优先级,解决了遍历开销;现在主流是 CFS,用 vruntime 和红黑树实现完全公平,还优化了交互式体验;而这一切都离不开时钟中断,它定期触发调度,保证系统能及时切换进程,不卡顿
软硬链接
一、硬链接
what?
给文件的 inode 起一个新的文件名映射,多个硬链接指向同一个 inode,本质是 "同一个文件的不同名字",就像引用一样,是不独立的
实现
-
在对应文件中将对应的inode编号所对应的文件名个数加一,ls命令可以展示count,同时加一个该inode与文件名的对应关系
-
硬链接的创建:
ln 原文件 硬链接文件本质是 ------ 在目录的 data block 中,新增一条 "硬链接文件名→原文件 inode 编号" 的目录项 -
关键细节(类比引用):
-
原文件和硬链接文件的 inode 编号完全相同;
-
inode 中的 "链接计数(link count)" 会 + 1(比如原文件 link count=1,创建一个硬链接后变成 2);
-
数据块和元数据(权限、大小、修改时间等)完全共享,修改任何一个,其他硬链接都会同步变化
-
二、软链接
what?
创建一个独立的新文件,该文件的 inode 数据块中存储的是 "原文件的路径",访问软链接时,系统会自动跳转去访问原文件,原文件与链接文件是相互独立的
实现
-
软链接的创建:
ln -s 原文件 软链接文件本质是 ------ 创建一个全新的 inode(有独立的 inode 编号),该 inode 的 data block 中只存储 "原文件的绝对 / 相对路径"(比如/home/user/test.txt) -
关键细节:
-
软链接文件有自己独立的 inode,link count 始终为 1;
-
软链接的文件类型标识为
l(用ls -l查看时,首字符是l); -
访问软链接时,系统会先读取其 data block 中的路径,再根据路径去查找原文件的 inode,最终访问原文件的数据
-
三、对比
| 对比维度 | 硬链接(Hard Link) | 软链接(Soft link) |
|---|---|---|
| inode 编号 | 与原文件完全相同(共享 inode) | 有独立的 inode 编号(独立文件) |
| 链接计数(link count) | 原文件和硬链接的 link count 同步增减 | 软链接自身 link count 始终为 1 |
| 存储内容 | 无独立存储,共享原文件的数据块和数据 | 独立数据块,存储原文件的路径(绝对 / 相对) |
| 原文件删除后 | 不影响,其他硬链接仍可正常访问(link count-1) | 软链接失效(变成 "断链",ls 查看呈红色闪烁) |
| 跨文件系统(如 ext4→NTFS) | 不支持(inode 编号仅在当前文件系统内唯一) | 支持(仅存储路径,与文件系统无关) |
| 指向对象 | 仅能指向文件,不能指向目录 | 可指向文件或目录 |
| 路径类型 | 仅支持相对路径(基于当前目录) | 支持绝对路径和相对路径 |
| 文件类型标识(ls -l) | 与原文件一致(如-表示普通文件,d表示目录) |
单独标识为l(link) |
| 权限设置 | 与原文件共享权限(设置硬链接权限会同步影响原文件) | 自身权限为rwxrwxrwx(但实际访问权限由原文件决定) |
四、小问题
1. 为什么硬链接不能指向目录?
-
核心原因:会导致目录树循环
-
补充:目录的默认 link count 是 2(自身目录项 + 父目录的
..指向),如果允许硬链接目录,会破坏目录树的层级结构和 link count 的计算逻辑。
2. 软链接的权限为什么是rwxrwxrwx?实际访问时以什么为准?
-
表面权限是
777,但这是 "假权限",实际访问软链接时,系统会穿透到原文件,以原文件的权限为准; -
比如软链接
link.txt权限是rwxrwxrwx,但原文件test.txt权限是rw-r--r--,则普通用户只能读取link.txt,不能修改
3. 硬链接的 link count 为 0 时,发生了什么?
- link count 为 0 表示没有任何文件名指向该 inode,系统会回收该 inode 及其对应的数据块,文件彻底删除
4. 软链接变成 "断链" 的常见原因?
-
原文件被删除或移动到其他路径
-
软链接使用相对路径,且软链接文件被移动到其他目录(比如在
/home创建ln -s test.txt link.txt,再把link.txt移到/root,访问时会找/root/test.txt,而原文件在/home)
软硬链接的核心区别在于是否共享 inode:硬链接是文件的别名,共享 inode 和数据,删除原文件不影响,不能跨文件系统、不能指向目录;软链接是独立文件,存储原文件路径,原文件删除后失效,支持跨文件系统和目录
僵尸进程
what?
僵尸进程是已经终止运行,但父进程未处理其返回信息的进程
僵尸进程的危害
-
进程进入僵尸状态之后,如果父进程一直不做处理,那么操作系统就要一直维护僵尸进程的退出信息,占用了CPU资源
-
同时,内存中还要一直维护进程的PCB进程信息控制块,如果一直不做处理的话,PCB的内存将会泄漏
- 进程pid是有限的,如果有大量的pid被僵尸进程占用,就不能创建新进程了
僵尸进程的处理
-
父进程调用wait()/waitpid(),回收子进程的退出信息
-
杀死父进程
为什么kill无法杀死僵尸进程?
-
核心:僵尸进程已经终止运行,不再执行任何代码,
kill信号的作用是 "通知进程执行特定操作"(如终止、暂停),但对已终止的进程无效; -
僵尸进程的残留是 "PCB 未回收",而非 "进程仍在运行",所以只能通过回收 PCB 的方式清除,不能用
kill