跳到主要内容
预计阅读 33 分钟

01|初识操作系统

操作系统是计算机世界的”隐形管家”。你看不见它的工作,但没有它,一切都将停摆。本章将带你揭开这层面纱,理解操作系统最核心的概念。

📋 开篇自测:你已经知道多少?

  1. 你能用一句话说清楚操作系统的核心职责是什么吗?
  2. 内核态和用户态的区别是什么?为什么需要这种区分?
  3. 你能列举出三种主流操作系统,并说出它们各自的典型应用场景吗?

一、操作系统到底是什么

想象你走进一家五星级酒店。你只需要告诉前台”我要一间海景房”,然后就有人帮你办好入住、打扫房间、调好空调、送上饮品。你不需要知道电力从哪里来、空调怎么运转、水管怎么铺设。操作系统扮演的正是这个”酒店管理系统”的角色——它把复杂的硬件资源管理起来,对上层应用提供简洁统一的服务。

1.1 从硬件到软件的鸿沟

一台裸机摆在你面前:CPU 只认识机器指令,内存只是一大片字节数组,硬盘上是连续的磁道和扇区,网卡收发的是电信号。如果没有操作系统,每个程序员都必须直接和这些硬件打交道——你得自己写代码去控制磁头寻道、自己管理内存地址分配、自己处理 CPU 在多个任务之间的切换。

这显然是不可接受的。操作系统的诞生,就是为了填补硬件和应用之间的鸿沟。

1.2 操作系统的四大核心职责

操作系统本质上是一个资源管理器服务提供者。它的核心职责可以归纳为四个方面:

+----------------------------------------------------------+
|                      应用程序层                            |
|   (浏览器、编辑器、数据库、游戏、你写的代码...)              |
+----------------------------------------------------------+
                          |
                     系统调用接口
                          |
+----------------------------------------------------------+
|                      操作系统内核                          |
|                                                          |
|  +--------------+  +------------+  +-----------+         |
|  |  进程管理     |  |  内存管理   |  |  文件系统  |         |
|  +--------------+  +------------+  +-----------+         |
|  +--------------+  +------------+                        |
|  |  设备管理     |  |  网络管理   |                        |
|  +--------------+  +------------+                        |
+----------------------------------------------------------+
                          |
                     硬件抽象层
                          |
+----------------------------------------------------------+
|                       硬件层                              |
|   (CPU、内存、硬盘、网卡、显卡、键盘、鼠标...)              |
+----------------------------------------------------------+

进程管理:决定哪个程序什么时候可以使用 CPU,如何创建和销毁进程,如何在多个进程之间公平分配计算资源。

内存管理:把有限的物理内存分配给多个进程使用,通过虚拟内存技术让每个进程都以为自己独享了整个内存空间。

文件系统:把硬盘上杂乱无章的磁道和扇区组织成我们熟悉的”文件夹 + 文件”结构,提供读写、权限控制等功能。

设备管理:统一管理各种硬件设备(键盘、鼠标、打印机、网卡等),为上层应用提供标准化的访问接口。

1.3 一个类比:操作系统是大楼的物业

把操作系统比作一栋写字楼的物业管理公司,会非常贴切:

物业管理操作系统
分配办公室给各家公司分配内存给各个进程
排班电梯、管理会议室调度 CPU、管理共享资源
管理停车场进出管理磁盘 I/O 读写
门禁系统防止闲杂人等权限管理防止非法访问
保安巡逻处理突发事件中断处理响应硬件事件

物业公司不直接产出效益,但没有它,整栋楼将陷入混乱。操作系统也是如此——它自己不完成用户的”业务目标”,但它让所有业务程序得以顺畅运行。

🤔 想一想 如果没有操作系统,两个程序同时想往屏幕上输出文字,会发生什么?


二、内核态与用户态:权力的边界

操作系统中最重要的概念之一,就是内核态(Kernel Mode)和用户态(User Mode)的区分。这不是一个可有可无的设计,而是整个系统安全和稳定的基石。

2.1 为什么需要两种运行模式

假设你开了一家公司,你会给每个员工配一把公司保险柜的钥匙吗?显然不会。普通员工只需要操作自己工位上的东西,只有财务主管才能打开保险柜。

CPU 的设计者也是这么想的。现代 CPU 至少提供两个特权级别:

  • 内核态(Ring 0):拥有最高权限,可以执行所有 CPU 指令,可以直接访问任何内存地址、操作任何硬件设备
  • 用户态(Ring 3):权限受限,不能直接执行特权指令,不能直接访问硬件,只能访问分配给自己的内存区域
     特权级别

     Ring 0 (内核态)    +---------------------------------+
     最高权限            |  操作系统内核代码                  |
                        |  - 硬件驱动程序                   |
                        |  - 中断处理                       |
                        |  - 内存管理                       |
                        |  - 进程调度                       |
                        +---------------------------------+

     Ring 3 (用户态)    +---------------------------------+
     受限权限            |  用户应用程序                      |
                        |  - 浏览器、编辑器                  |
                        |  - 数据库服务                      |
                        |  - 你编写的程序                    |
                        +---------------------------------+

x86 架构实际上定义了 Ring 0 到 Ring 3 共四个特权级,但大多数操作系统只使用了 Ring 0 和 Ring 3 这两个。

2.2 内核态与用户态的切换

用户程序运行在用户态,当它需要操作系统提供服务时(比如读文件、发送网络数据),就必须通过系统调用切换到内核态。这个切换过程大致如下:

用户程序正在执行
      |
      | 需要读取文件
      |
      v
发起系统调用 (如 read())
      |
      | ------- 用户态/内核态 边界 -------
      |
      v
CPU 切换到内核态
保存用户程序上下文
      |
      v
内核执行对应的服务代码
(真正执行磁盘读取操作)
      |
      v
执行完毕,恢复用户程序上下文
CPU 切换回用户态
      |
      | ------- 用户态/内核态 边界 -------
      |
      v
用户程序继续执行
(获得读取结果)

这个切换是有代价的。每次从用户态切到内核态,CPU 需要保存当前程序的寄存器状态、切换页表、跳转到内核代码执行,完成后再反向恢复。这个过程通常需要几微秒的时间。虽然看起来很短,但如果一个程序每秒进行数十万次系统调用,累积起来的开销就相当可观了。

2.3 三种进入内核态的方式

用户态进入内核态,通常有三条路径:

系统调用(System Call):用户程序主动请求内核服务。这是最常见的方式,比如 open()、read()、write()、fork() 等。

中断(Interrupt):外部硬件设备发出信号通知 CPU。比如键盘按下一个键、网卡收到一个数据包、定时器到期。CPU 会暂停当前任务,跳转到内核中对应的中断处理函数。

异常(Exception):程序执行过程中发生了错误或特殊情况。比如除以零、访问了非法的内存地址(段错误)、执行了特权指令。内核会接管处理这些异常。

🤔 想一想 一个 printf(“hello”) 看起来很简单,它背后会触发用户态到内核态的切换吗?为什么?


三、系统调用:应用程序与内核之间的”窗口”

3.1 什么是系统调用

系统调用是操作系统提供给用户程序的一组”官方接口”。你可以把它理解成政府部门的办事大厅——你想办什么事,到对应的窗口去填表、提交材料就行。你不需要知道政府内部是怎么运作的,只需要知道大厅提供哪些服务、怎么使用。

在 Linux 系统中,系统调用编号已超过 460 个(以 x86-64 架构、Linux 6.x 内核为例,其中包含少量保留编号,且随内核版本持续增长)。它们覆盖了操作系统的所有核心功能:

类别常用系统调用作用
进程控制fork, exec, exit, wait创建/替换/终止/等待进程
文件操作open, read, write, close打开/读/写/关闭文件
内存管理mmap, brk, munmap映射内存、调整堆空间
设备操作ioctl, read, write控制设备、读写设备
网络通信socket, bind, listen, accept创建套接字、网络连接
信息维护getpid, time, uname获取进程 ID、时间、系统信息

3.2 系统调用的执行过程

以 Linux x86-64 架构为例,一个系统调用的完整执行过程如下:

  用户空间                                   内核空间

  应用程序代码
       |
       | 1. 将系统调用号放入 rax 寄存器
       |    将参数放入 rdi, rsi, rdx 等寄存器
       |
       | 2. 执行 syscall 指令
       |
       +-------- CPU 特权级切换 -------->  3. CPU 跳转到系统调用入口
                                              (entry_SYSCALL_64)
                                          |
                                          | 4. 根据 rax 中的调用号
                                          |    查找 sys_call_table
                                          |
                                          | 5. 调用对应的内核函数
                                          |    (如 sys_read, sys_write)
                                          |
                                          | 6. 将返回值放入 rax
                                          |
       <-------- CPU 特权级切换 --------+  7. 执行 sysret 指令
       |
       | 8. 用户程序获得返回值
       |    继续执行
       v

你平时写代码时调用的 read()、write() 这些函数,其实并不是直接的系统调用。它们是 C 标准库(glibc)提供的包装函数——glibc 帮你处理了寄存器设置、syscall 指令调用、错误码转换等琐碎工作,让你可以像调用普通函数一样使用系统调用。

3.3 系统调用 vs 库函数

初学者容易混淆系统调用和库函数。来看一个对比:

printf("hello, world\n");    <-- 库函数 (glibc)
     |
     | 内部会调用
     v
write(1, "hello, world\n", 13);  <-- 系统调用包装
     |
     | 通过 syscall 指令
     v
sys_write()                   <-- 内核中真正的系统调用实现

printf() 是 glibc 的库函数,它内部做了格式化、缓冲区管理等工作,最终当缓冲区满或者遇到换行符时,才会调用 write() 系统调用。所以一次 printf() 不一定立刻触发一次系统调用——glibc 会帮你做批量处理来减少切换开销。


四、操作系统的内核架构

4.1 宏内核 vs 微内核

操作系统的内核设计,历史上有两大流派:

宏内核(Monolithic Kernel):把进程管理、内存管理、文件系统、设备驱动、网络协议栈等所有功能都放在内核空间里运行。Linux、FreeBSD 采用的就是这种设计。

+------------------------------------------+
|              用户空间                      |
|   应用A    应用B    应用C    应用D          |
+------------------------------------------+
|              内核空间 (全部在 Ring 0)       |
|  +--------+  +--------+  +----------+   |
|  |进程调度 |  |内存管理 |  |文件系统   |   |
|  +--------+  +--------+  +----------+   |
|  +--------+  +--------+                 |
|  |设备驱动 |  |网络协议栈|                 |
|  +--------+  +--------+                 |
+------------------------------------------+
|              硬件                         |
+------------------------------------------+

优势:各模块之间直接函数调用,性能极高。 劣势:任何一个模块出了 bug(比如一个有缺陷的驱动),都可能导致整个内核崩溃。

微内核(Microkernel):内核只保留最基本的功能(进程间通信、基本调度、地址空间管理),其他功能(文件系统、设备驱动、网络协议栈)都作为独立的用户态进程运行。QNX、Minix、seL4 是典型代表。

+------------------------------------------+
|              用户空间                      |
|  应用A   应用B   文件系统   设备驱动       |
|                  服务器     服务器          |
+------------------------------------------+
|              内核空间 (极小)               |
|  +--------+  +--------+  +----------+   |
|  |IPC通信  |  |基本调度 |  |地址空间管理|   |
|  +--------+  +--------+  +----------+   |
+------------------------------------------+
|              硬件                         |
+------------------------------------------+

优势:隔离性好,一个服务崩溃不会拖垮整个系统,安全性和可靠性高。 劣势:各服务之间通信需要通过 IPC(进程间通信),性能开销较大。

混合内核:取两者之长。macOS/iOS 的 XNU 内核、Windows NT 内核都属于混合内核——核心功能在内核态运行获取性能,部分服务以可加载模块或用户态进程的形式提供灵活性。

4.2 Linux 的模块化宏内核

Linux 采用宏内核架构,但它引入了**可加载内核模块(LKM, Loadable Kernel Module)**机制来弥补宏内核的灵活性不足。你可以在运行时动态地加载或卸载内核模块(比如设备驱动),而不需要重新编译整个内核。

$ lsmod                   # 查看当前加载的内核模块
$ insmod mydriver.ko      # 加载一个内核模块
$ rmmod mydriver          # 卸载一个内核模块

这种设计让 Linux 既保持了宏内核的高性能,又获得了接近微内核的灵活性。


五、主流操作系统对比

5.1 三大操作系统家族

现代操作系统主要分为三大家族:

                        操作系统
                           |
            +--------------+--------------+
            |              |              |
         Unix-Like      Windows NT      其他
            |              |              |
     +------+------+      |         +----+----+
     |      |      |      |         |         |
   Linux  macOS  BSD    Win10/11   RTOS    嵌入式OS
     |      |      |               |
  +--+--+   |   +--+--+       FreeRTOS
  |     |   |   |     |       VxWorks
Ubuntu  |  iOS Free  Open
CentOS  |      BSD   BSD
Debian  |
Android |
        macOS/iOS

5.2 横向对比

特性LinuxWindowsmacOS
内核类型宏内核(模块化)混合内核(NT)混合内核(XNU)
源码开源(GPL)闭源部分开源(Darwin)
主要应用场景服务器、云、嵌入式桌面、办公、游戏创意工作、开发
文件系统ext4, XFS, BtrfsNTFS, ReFSAPFS, HFS+
包管理apt, yum, pacmanMSI, MSIXHomebrew, pkg
多用户支持天然多用户多用户(不如Linux)多用户
实时性可选RT补丁不支持硬实时不支持硬实时

5.3 为什么服务器世界选择了 Linux

根据行业统计数据,全球超过 90% 的公有云工作负载运行在 Linux 上。这并非偶然,而是由多个因素共同决定的:

  • 开源免费:无需支付许可费,可以自由修改和分发
  • 稳定高效:Linux 内核经过数十年的打磨和千万开发者的审查
  • 生态丰富:几乎所有服务端软件(Nginx、MySQL、Redis、Kafka…)都原生支持 Linux
  • 可定制性强:从手表(Android Wear)到超级计算机(全球 TOP500 超算 100% 运行 Linux),Linux 都能胜任
  • 命令行优先:适合自动化运维和远程管理

🤔 想一想 Android 是基于 Linux 内核的,那它算 Linux 操作系统吗?它和我们通常说的 Linux 发行版有什么关键区别?


六、操作系统的启动过程

6.1 从按下电源键到看见桌面

很多人从来没有想过,按下电源键之后到底发生了什么。这个过程其实精密得像一场接力赛:

1. 通电
   |
   v
2. CPU 从固定地址开始执行
   - 早期 8086: 0xFFFF0 (20位地址空间)
   - 现代 x86 (80386+): 0xFFFFFFF0 (4GB以下16字节)
   |
   v
3. BIOS/UEFI 固件启动
   - 硬件自检 (POST)
   - 检测CPU、内存、硬盘、显卡等
   |
   v
4. 加载引导程序 (GRUB/systemd-boot)
   - 从硬盘的引导扇区 (MBR/GPT) 读取
   - 显示操作系统选择菜单
   |
   v
5. 加载内核镜像到内存
   - 解压内核
   - 初始化基本硬件
   |
   v
6. 内核初始化
   - 建立页表,启动虚拟内存
   - 初始化中断处理
   - 初始化各子系统(进程、内存、文件、网络)
   |
   v
7. 启动第一个用户态进程 (init / systemd)
   - PID = 1
   - 所有其他进程的祖先
   |
   v
8. init/systemd 按配置启动系统服务
   - 网络服务、SSH、日志、定时任务等
   |
   v
9. 启动登录管理器或Shell
   - 图形界面 (GDM/LightDM) 或命令行
   |
   v
用户可以开始使用系统

6.2 BIOS vs UEFI

传统的 BIOS(Basic Input/Output System)和现代的 UEFI(Unified Extensible Firmware Interface)都是固件层面的程序,它们的职责是在操作系统启动之前完成硬件初始化。

特性BIOSUEFI
诞生年代1975 年(概念起源于 CP/M)/ 1981 年(IBM PC BIOS)2005 年(UEFI Forum 成立)/ 2006 年(UEFI 2.0 规范发布)
分区表MBR(最大 2TB)GPT(最大 18EB)
运行模式16 位实模式32/64 位保护模式
启动速度较慢较快
安全启动不支持支持 Secure Boot
界面文字界面可图形化

如今新出厂的计算机几乎全部使用 UEFI。它支持更大的磁盘、更快的启动速度,并且可以通过 Secure Boot 验证引导程序的签名,防止恶意软件篡改启动过程。


七、动手实践:观察你的操作系统

理论讲了很多,现在来动手看看你正在使用的操作系统。

7.1 在 Linux 上探索

# 查看内核版本
uname -r
# 输出示例: 6.5.0-14-generic

# 查看操作系统发行版信息
cat /etc/os-release

# 查看 CPU 信息
lscpu

# 查看内存信息
free -h

# 查看当前运行的进程数
ps aux | wc -l

# 查看系统已运行时间
uptime

# 查看系统调用次数统计(执行 ls 命令)
strace -c ls /tmp 2>&1 | tail -20

7.2 观察系统调用

strace 是一个强大的工具,它能让你”窥视”一个程序到底调用了哪些系统调用:

# 追踪 ls 命令的系统调用
strace ls /tmp 2>&1 | head -30

# 你会看到类似这样的输出:
# execve("/usr/bin/ls", ["ls", "/tmp"], ...) = 0
# brk(NULL)                           = 0x55a8c7b43000
# openat(AT_FDCWD, "/etc/ld.so.cache", ...) = 3
# read(3, "\177ELF..."..., 832)       = 832
# mmap(NULL, 8192, ...)               = 0x7f3a2c5b0000
# ...

即使一个简单的 ls 命令,背后也涉及几十个系统调用:execve 启动程序、openat 打开目录、getdents64 读取目录项、write 输出结果。这就是操作系统在幕后默默完成的工作。

🤔 想一想 运行 strace -c echo “hello” 统计一下,一个最简单的 echo 命令需要多少次系统调用?这些调用分别在做什么?


八、本章总结

本章我们建立了对操作系统的整体认知框架:

+---------------------------------------------------+
|                  核心概念速览                        |
+---------------------------------------------------+
|                                                   |
|  操作系统 = 资源管理器 + 服务提供者                   |
|                                                   |
|  四大职责: 进程管理 | 内存管理 | 文件系统 | 设备管理   |
|                                                   |
|  内核态 vs 用户态: 保护机制,通过系统调用穿越边界       |
|                                                   |
|  内核架构: 宏内核(Linux) / 微内核(QNX) / 混合(XNU)   |
|                                                   |
|  启动过程: 固件 -> 引导器 -> 内核 -> init -> 服务     |
|                                                   |
+---------------------------------------------------+

操作系统是后续所有章节的基础。理解了它的角色和基本架构,你就能更好地理解进程、线程、内存、文件系统等具体话题。


📝 结尾自测:检验你的收获

  1. 操作系统的四大核心职责分别是什么?请各用一句话描述。
  2. 用户态程序进入内核态有哪三种方式?各自的触发场景是什么?
  3. 宏内核和微内核的核心区别是什么?Linux 采用哪种架构?它如何弥补灵活性不足?
  4. 系统调用和库函数有什么区别?printf() 和 write() 分别属于哪一种?
  5. 画出从按下电源键到用户登录的完整启动流程(至少包含 6 个阶段)。

购买课程解锁全部内容

系统底层入门:10 章掌握操作系统核心

¥29.90