操作系统结构
1.3.1 说内核运行在内核态,但没说”哪些东西该放进内核”。这一节讲的正是这个设计决策。
五种结构可以放在同一根轴上看:内核里装多少东西。装得越多性能越高(不用来回切模式),装得越少可靠性越好(出问题的代码少)——五种结构就是这条轴上的五个位置。
机制
分层法
把内核分成若干层,每层只能调用紧邻的低一层。
优点是便于调试和验证、易于扩充和维护:验证第
缺点有两条:仅可调用紧邻的低一层,效率低——一个请求要逐层传递下去,每层都有开销;难以合理定义各层的边界——很多功能之间是互相依赖的,硬要排成线性次序并不自然。
模块化
把内核划分为若干模块,各模块之间通过接口相互协作,不再要求严格的层次次序。内核由一个主模块和若干可加载的内核模块构成。
优点是模块间逻辑清晰、易于维护,并且支持动态加载新的内核模块——需要某个设备驱动时才装进来,不需要就卸掉。
缺点是模块间的接口定义未必合理实用,且模块之间相互依赖,难以调试和验证——这恰好是分层法优点的反面。
宏内核(大内核)
把操作系统的主要功能模块都作为一个紧密整体运行在内核态。
优点是性能高:各功能之间是普通的函数调用,不需要任何模式切换。
缺点是内核庞大、结构混乱、难以维护,且可靠性差——内核态的一个错误就可能拖垮整个系统,而内核里的代码越多,出错的机会越大。
微内核
只把最基本的功能保留在内核,把那些不需要在内核态执行的功能移到用户态执行。
内核中通常只保留:低级进程/线程管理、低级存储管理、中断和陷入处理、进程间通信。而文件系统、设备驱动、网络协议栈等都作为用户态的服务进程运行。
优点是内核小、可靠性高、可扩展性好、可移植性好——某个服务崩了只是一个用户态进程挂掉,可以重启,不会拖垮系统。
缺点是性能开销大,原因见下面的边界分析。
外核
内核负责为程序分配硬件资源,并保证资源使用的安全(不越权),而把资源的”抽象”工作交给上层。
普通操作系统给你的是”文件”和”虚拟内存”这些抽象;外核直接给用户程序分配”未经抽象的”硬件资源——比如直接给你几个物理磁盘块、几个物理页框,由应用程序自己决定怎么用。
优点是应用可以更灵活地使用硬件(数据库可以按自己的方式管理磁盘,不必迁就通用文件系统),并且减少了虚拟硬件资源的映射层,可以提升效率。
缺点是降低了系统的一致性,也使系统变得更复杂。
边界
微内核为什么性能差
这是本节唯一需要论证的地方,也是最常考的”为什么”。
在宏内核中,一次读文件是这样的:用户程序执行系统调用进入内核态 → 内核里的文件系统代码直接以函数调用的方式调设备驱动 → 返回用户态。全程只有两次模式切换。
在微内核中,文件系统是一个用户态的服务进程,于是同一次读文件变成:用户程序 → 陷入内核 → 内核把请求通过进程间通信转发给文件系统服务进程 → 切换到该进程 → 文件系统服务进程又要读磁盘,于是它再陷入内核、内核再转发给设备驱动服务进程……
每一次服务之间的协作,都要付出”模式切换 + 进程切换 + 消息传递”的代价,而在宏内核里这只是一次函数调用。
所以微内核的开销不在于”内核小”,而在于”被拆开的部分之间必须靠昂贵的方式通信”。
微内核不是”没有内核”
“微”指的是内核里保留的功能少,不是没有内核。
微内核仍然运行在内核态,仍然掌握着最基本的机制——进程管理、内存管理的最低层、中断处理、进程间通信。这四样是无论如何都搬不出去的:进程间通信本身就是搬出去的那些服务赖以协作的手段,它必须留在内核。
同理,宏内核也不是”没有模块”——宏内核完全可以是模块化实现的(Linux 就是),只是这些模块统统运行在内核态。
判据:区分宏内核与微内核,看的是”服务运行在哪个模式”,不是”代码有没有分模块”。
分层法与模块化的优缺点恰好互补
这一对值得放在一起记,因为它们的优缺点是镜像的:
分层法限制严格(只能调低一层),因此易于验证、但效率低且边界难定。
模块化限制宽松(模块间自由协作),因此灵活、易维护、可动态加载,但相互依赖导致难以调试验证。
一句话:分层法用”限制”换”可验证性”,模块化用”自由”换”灵活性”。
五种结构在同一根轴上的位置
把它们按”内核里装多少”排开,规律非常清楚:
宏内核装得最多 → 性能最高、可靠性最差。 模块化 / 分层法是宏内核内部的组织方式 → 仍然都在内核态。 微内核装得最少 → 可靠性最高、性能最差。 外核则换了一个维度——它不是”装多少”,而是”抽不抽象”:内核只做分配与保护,不做抽象。
做选择题时,看到”效率高/内核庞大”想宏内核;看到”可靠性、可扩展、可移植”想微内核;看到”只保护和复用硬件、把控制权交给上层”想外核。
对照速查
| 结构 | 核心思想 | 优点 | 缺点 |
|---|---|---|---|
| 分层法 | 每层只能调用紧邻的低一层 | 便于调试和验证、易扩充维护 | 效率低;层的边界难以合理定义 |
| 模块化 | 主模块 + 可加载内核模块 | 逻辑清晰易维护、支持动态加载 | 接口未必合理;相互依赖,难调试验证 |
| 宏内核 | 主要功能都在内核态 | 性能高(函数调用) | 内核庞大、可靠性差 |
| 微内核 | 只保留最基本功能在内核 | 可靠、可扩展、可移植 | 性能开销大(模式切换 + IPC) |
| 外核 | 内核只做分配与保护,不做抽象 | 灵活、减少映射层、效率高 | 降低一致性、系统更复杂 |
| 微内核保留在内核的四样 | |
|---|---|
| ① | 低级进程 / 线程管理 |
| ② | 低级存储管理 |
| ③ | 中断和陷入处理 |
| ④ | 进程间通信(搬不出去,它是其余服务协作的手段) |
| 常见题眼 | 多半对应 |
|---|---|
| 效率高、内核庞大、服务都在内核态 | 宏内核 |
| 只保留最基本机制、服务外移、可靠可扩展 | 微内核 |
| 按层调用、下层为上层服务、便于验证 | 分层法 |
| 高内聚低耦合、可动态加载 | 模块化 |
| 只负责保护和复用硬件、把控制权交给上层 | 外核 |
考点
- 五种结构及其优缺点,分层法与模块化的优缺点互补
- 微内核性能差的原因是”模式切换 + 进程切换 + 消息传递”取代了函数调用
- 微内核不是没有内核;宏内核也可以是模块化的
- 判据:宏内核 vs 微内核看”服务运行在哪个模式”,不看代码是否分模块
- 进程间通信必须留在微内核里,因为其余服务靠它协作
- 外核的特点是”不做抽象”,直接分配未经抽象的硬件资源
链接
- 🏠 返回总览:操作系统第 1 章:计算机系统概述总览
- ⬅️ 上一节:1.3.3 系统调用
- ➡️ 下一节:1.5 操作系统引导
- 🔗 内核包含哪四部分,见 1.3.1 处理器运行模式
- 🔗 进程间通信的三种方式,见 2.1.5 进程的通信
- 📖 名词库:第 1 章名词库