操作系统经典可视化

三大经典机制,一页全跑通:进程调度看甘特图、 页面置换数缺页率、死锁避免求安全序列。 左侧调参数,右侧实时更新,所有数值保留两位小数。

FCFS / SJF / RR / 优先级 FIFO / LRU / OPT 银行家算法 甘特图 安全序列

1公式与参数

进程调度关注三个时间指标:完成时间 $C_i$、周转时间 $T_i$、等待时间 $W_i$。 调度算法的目标通常是让平均等待时间最小:

$$T_i = C_i - A_i, \qquad W_i = T_i - B_i$$
$$\bar{W} = \frac{1}{n}\sum_{i=1}^{n} W_i, \qquad \bar{T} = \frac{1}{n}\sum_{i=1}^{n} T_i$$

$A_i$ 是到达时间,$B_i$ 是服务时间(突发时间)。带权周转时间 $T_i / B_i$ 更能反映长短作业的公平性。

时间片轮转(RR)的关键参数是时间片 $q$:每个进程最多连续运行 $q$ 个时间单位, 然后被放回队尾。若 $q \to \infty$ 则退化为 FCFS;若 $q \to 0$ 则上下文切换开销主导。

$$T_{\text{RR}}(n, q) \;\approx\; \frac{n \cdot q}{n \cdot q + n \cdot \text{switch}} \cdot \text{有效利用率}$$

页面置换的核心指标是缺页率。设访问序列长度为 $L$,缺页次数为 $F$:

$$\text{缺页率} = \frac{F}{L} \times 100\%, \qquad \text{命中率} = 1 - \text{缺页率}$$

FIFO 可能出现 Belady 异常(增加页框反而缺页更多);LRU 和 OPT 属于栈算法,不会出现该异常。

银行家算法通过判断系统能否处于安全状态来避免死锁。 令 $\text{Need} = \text{Max} - \text{Allocation}$,$\text{Work}$ 为当前可用资源:

$$\text{若 } \exists\, i \text{ 满足 } \text{Need}_i \le \text{Work} \;\Longrightarrow\; \text{Work} \leftarrow \text{Work} + \text{Allocation}_i$$

反复执行直到所有进程都能完成(Finish 全为 true),则存在安全序列, 系统处于安全状态;否则若某时刻找不到满足条件的进程,说明可能发生死锁。

符号 数学含义 通俗解释
Aᵢ 到达时间 进程什么时候进入就绪队列。如果为 0,表示一开始就在。
Bᵢ 服务时间 / 突发时间 进程需要 CPU 运行多久才能完成。本页取 2~7 个时间单位。
Cᵢ 完成时间 进程最后一次离开 CPU 的时刻。
Tᵢ / Wᵢ 周转 / 等待时间 周转 = 完成 − 到达;等待 = 周转 − 服务。等待时间是调度算法的核心优化目标。
q 时间片(RR) RR 算法每个进程一次最多运行的时间。太小开销大,太大退化为 FCFS。
F 缺页次数 访问的页不在内存时需要从磁盘调入,这一次访问就算一次缺页。
Max / Alloc 最大需求 / 已分配 银行家算法里每个进程"最多要多少"和"现在拿着多少"。
Need 尚需资源 Need = Max − Allocation。等于 0 表示这个进程已经拿够了。
Work 当前可用资源 安全性检查时用来模拟"如果我手上有这些资源,能先让谁跑完"。

2交互模拟

调整算法与进程数,右侧甘特图会立即重画。鼠标悬停在色块上可以看到该进程的运行区间。

进程越多,不同调度策略的差距越明显。
进程数
5
总完成时间
0
平均等待时间
0.00
平均周转时间
0.00
进程 到达 服务 优先级 开始 完成 周转 等待

选择置换算法与页框数,右侧会逐列展示每一步的页框状态。 红色列表示缺页,绿色列表示命中。

物理内存中能同时容纳的页数。太少会频繁缺页(抖动)。
用逗号或空格分隔的数字,代表依次访问的页号。
总访问次数
0
缺页次数
0
命中次数
0
缺页率
0.00%
等待运行…

使用经典银行家算法示例(5 个进程、3 种资源)。点击下方按钮逐步执行安全性检查, 观察 Work 如何随着进程完成而增长,以及安全序列如何被构建出来。

A = 10, B = 5, C = 7
这是一个经典的教科书数据。所有进程完成后,资源应全部归还。
逐步动画时每一步的等待时间。
已检查进程
0 / 5
当前 Work
3 3 2
状态
待运行
安全序列长度
0

Allocation 已分配

Max 最大需求

Need 尚需 = Max − Alloc

Work + Finish

安全序列: 尚未开始
等待运行…(点击「逐步运行」或「单步」)

3深入理解

标准介绍

进程调度是操作系统的核心职责之一,决定就绪队列中哪个进程获得 CPU。 经典算法包括 FCFS(先来先服务)、SJF(短作业优先,可抢占版本为 SRTF)、 RR(时间片轮转,现代分时系统的基础)与优先级调度。 页面置换解决虚拟内存中"内存满了该换出哪一页"的问题, FIFO 最简单但可能出现 Belady 异常;LRU 利用时间局部性,接近最优; OPT(Belady 最优)需要预知未来,只能作为理论下界。 死锁避免通过银行家算法(Dijkstra, 1965)在分配前预判系统是否仍处于安全状态, 是"死锁预防、避免、检测、恢复"四类策略中最具代表性的一种。

通俗介绍

进程调度像食堂打饭:FCFS 就是排队,先来先打; SJF 是让"只打一个菜的人"先打,提高整体吞吐; RR 是每个人最多打 30 秒,时间到了就排到队尾——分时系统靠它让每个人都能"轮得到"。 页面置换像书桌太小:只能放几本书,来了新书就要把一本拿走。 FIFO 是"最早放上桌的先拿走",LRU 是"最近最少翻的拿走", OPT 是"以后最久不会用到的拿走"——只有神仙才能预知未来。 银行家算法像银行贷款:在放贷前先算一笔账, 确保即使所有客户都来提款,银行也不会破产。如果算下来无法满足,就先拒绝这笔贷款。

解决了什么问题

  • CPU 利用率与响应时间:让多个进程公平、高效地共享一颗 CPU。
  • 内存容量不足:虚拟内存 + 页面置换让程序可以使用超过物理内存的空间。
  • 并发资源竞争:银行家算法在分配前预判,避免系统进入死锁状态。
  • 局部性原理的工程化:LRU、Clock 等算法把"时间/空间局部性"变成可执行的策略。
  • 吞吐量与公平性的权衡:不同算法给出不同的折中方案,供不同场景选择。

为什么重要

  • 它们是操作系统课程的三大经典章节,几乎每本教材都会花大量篇幅讲解。
  • 它们是实际系统性能的直接决定因素:调度策略影响服务器吞吐,置换算法影响程序响应。
  • 它们展示了理论与工程的结合:LRU 是理论最优的近似,Clock 是 LRU 的廉价实现。
  • 它们是并发与资源管理思想的源头:现代容器调度、K8s 资源分配都能看到它们的影子。
  • 它们让抽象的"公平""安全""局部性"变成了可量化、可比较的指标。

应用场景

  • Linux 调度器:CFS(完全公平调度)基于红黑树,是 RR 思想的高级演化。
  • 实时系统:优先级调度配合优先级继承,保证关键任务按时完成。
  • 数据库缓冲池:LRU 及其变种(LRU-K、2Q)决定哪些页留在内存中。
  • Web 缓存:Redis、CDN 的缓存淘汰策略大量借鉴 LRU、LFU、Clock。
  • 分布式资源分配:银行家算法的思想被用于分布式事务、容器编排的资源预留。
  • 编译器寄存器分配:图着色算法与"安全分配"的思想同源。

缺陷与局限

  • SJF 需要预知未来:真实系统无法准确知道进程还要运行多久,只能靠历史估计。
  • RR 的时间片难以调优:太小导致上下文切换开销大,太大退化为 FCFS。
  • LRU 硬件实现昂贵:需要为每个页维护时间戳,实际多用 Clock 近似。
  • OPT 不可实现:只能作为理论下界,用来评估其他算法的优劣。
  • Belady 异常:FIFO 在某些访问序列下增加页框反而缺页更多。
  • 银行家算法要求静态已知:需要预先知道每个进程的最大需求,实际中很难获取。
  • 安全性检查开销大:$O(n^2 m)$ 的检查频率高时会影响性能,实际系统很少原样使用。

动手建议

把进程调度切到 FCFS,记下平均等待时间; 再切到 SJF,你会发现平均等待时间明显下降——因为短作业不再被长作业堵在后面。 再切到 RR,把时间片从 1 调到 5: 时间片很小时平均等待时间可能反而变大(切换开销),时间片太大则退化为 FCFS。 页面置换里,把帧数从 3 调到 4,观察三种算法缺页率的变化—— FIFO 有时会出现"增加帧数、缺页率反而上升"的 Belady 异常,LRU 和 OPT 则单调下降。 最后到死锁标签页,一步步跑银行家算法:注意 Work 是如何从 [3,3,2] 增长到 [10,5,7] 的, 每一步选择的进程都是"当前 Work 能满足其 Need"的那个。这就是安全序列的本质。