操作系统笔记¶
操作系统位于应用程序和硬件之间。向上,它给程序提供进程、线程、虚拟地址、文件和套接字等稳定抽象;向下,它管理 CPU、内存、磁盘、网卡和各种设备,并阻止彼此不可信的程序越界干扰。
如果没有操作系统,每个程序都要自己处理键盘中断、磁盘扇区、物理内存地址和设备时序。更困难的是,多个程序会同时争用同一批硬件资源。操作系统解决的核心问题因此不是“怎样封装几个函数”,而是:
如何在共享而有限的硬件上,为许多程序提供方便、高效、可靠并且彼此隔离的运行环境?
三个核心角色¶
| 角色 | 解决的问题 | 典型抽象 |
|---|---|---|
| 抽象机器 | 硬件接口过于具体且差异很大 | 进程、虚拟内存、文件、套接字 |
| 资源管理器 | 多个任务争用有限资源 | 调度、内存分配、缓存、I/O 队列 |
| 隔离与保护者 | 程序可能出错,甚至具有恶意 | 用户态、页表权限、访问控制、命名空间 |
这三个角色经常互相拉扯。更强的抽象可能增加额外开销;更高的吞吐量可能损害交互延迟;更严格的隔离往往需要更多检查或硬件支持。学习操作系统的重点不是背诵某个算法,而是看清这些权衡发生在哪里。
一个最小但完整的例子¶
应用程序读取文件时,常见代码只有一行:
这行代码背后至少涉及:
用户态函数
-> 系统调用入口
-> 文件描述符表
-> 虚拟文件系统
-> inode 与页缓存
-> 必要时提交块 I/O
-> 驱动配置设备和 DMA
-> 中断通知完成
-> 数据复制或映射到用户缓冲区
-> 返回用户态
如果数据已经在页缓存中,磁盘可能完全不参与;如果数据不在缓存中,线程可能睡眠,让出 CPU,直到设备完成 I/O。这个例子把特权级、调度、虚拟内存、文件系统、设备驱动和并发同步连成了一条线,也是本笔记最后的综合案例。
全局心智模型¶
可以把操作系统看成许多受事件驱动的状态机。事件可能来自系统调用、时钟中断、缺页异常、设备中断或其他 CPU;内核根据当前状态修改数据结构,并决定下一步运行谁、映射什么、唤醒谁或向哪个设备发出请求。
这个模型比“内核是一个一直运行的大程序”更准确:没有用户工作或外部事件时,内核通常没有独立的业务要做;它主要在需要仲裁和服务时获得控制权。
内容结构¶
| 章节 | 主要问题 |
|---|---|
| 第1章 | 操作系统怎样把硬件变成受保护的服务? |
| 第2章 | 怎样表示执行流,并在有限 CPU 上调度它们? |
| 第3章 | 并发访问为何出错,怎样同步并避免死锁? |
| 第4章 | 怎样让每个进程拥有独立、按需扩展的地址空间? |
| 第5章 | 怎样持久保存数据并高效驱动慢速、异步的设备? |
| 第6章 | 怎样建立安全边界,并在一台机器上运行多个系统视图? |
| 第7章 | 怎样串起完整路径,并用工具验证自己的判断? |
推荐阅读顺序¶
第一次学习建议按章节顺序阅读。第1章给出特权转换和事件入口;第2章解释“谁正在运行”;第3章解释“多个执行流怎样共享状态”;第4章说明地址如何翻译;第5章再把持久化数据和设备接入这套模型。
如果已有基础,可以围绕具体问题纵向阅读:
- 调试程序卡住:进程状态 → 条件变量 → 死锁 → I/O 等待 → 诊断工具。
- 调试内存抖动:地址空间 → 页表与 TLB → 缺页 → 页面置换 → 页缓存。
- 调试文件读取慢:文件与 inode → 页缓存 → 块 I/O → 驱动与 DMA → 综合案例。
- 理解容器:保护机制 → 虚拟内存 → 进程 → namespace/cgroup → 容器。
学习方法¶
操作系统的概念必须和可观察证据对应。看到“上下文切换昂贵”时,应继续问:保存了哪些状态,缓存和 TLB 是否受影响,工具能否测到切换频率?看到“读取文件”时,应继续问:命中页缓存了吗,线程是否睡眠,实际块设备 I/O 有多少?
建议对每个机制做三层追问:
- 抽象层:它向上提供了什么稳定接口?
- 机制层:内核和硬件实际维护了哪些状态?
- 策略层:当选择不唯一时,系统采用什么权衡?
机制回答“能不能做到”,策略回答“应该怎样选择”。页表是机制,页面置换算法是策略;定时器中断和上下文保存是机制,调度算法是策略。把二者分开,很多概念会清楚得多。
实验边界¶
笔记中的命令优先采用只读观测方式。strace、ps、vmstat、iostat、perf stat 等工具的可用性取决于操作系统、内核配置和权限;执行前应先确认目标进程和运行环境,不在生产系统上盲目进行高开销跟踪。
继续阅读前,可以先带着三个问题:
- 为什么普通函数调用不能直接替代系统调用?
- 为什么一个线程等待磁盘时,另一个线程还能使用 CPU?
- 为什么程序访问的地址通常不是内存条上的真实物理地址?
后续章节会逐步建立回答这些问题所需的模型。