操作系统概述
课程概述
本教程全面介绍操作系统的基本概念、架构类型和核心机制,帮助你建立完整的操作系统知识框架,理解OS在计算机系统中的关键作用。
学习目标:
- 理解操作系统的演进历史和设计哲学
- 掌握宏内核、微内核、混合内核的差异
- 深入理解用户态与内核态的切换机制
- 掌握系统调用的工作原理
- 对比Linux、Windows、macOS的架构差异
1. 操作系统的作用与功能
1.1 什么是操作系统
┌─────────────────────────────────────────────────────────────┐
│ 操作系统在计算机系统中的位置 │
└─────────────────────────────────────────────────────────────┘
应用层(Application Layer)
┌────────────────────────────────────┐
│ 用户应用程序 │
│ 浏览器 编辑器 游戏 数据库 ... │
└────────────────┬───────────────────┘
│ 系统调用接口
│ (System Call API)
┌────────────────▼───────────────────┐
│ 操作系统(OS) │
│ ┌──────────────────────────────┐ │
│ │ 进程管理 内存管理 文件系统 │ │
│ │ 设备驱动 网络协议栈 安全 │ │
│ └──────────────────────────────┘ │
└────────────────┬───────────────────┘
│ 硬件抽象层
│ (HAL)
┌────────────────▼───────────────────┐
│ 硬件层(Hardware) │
│ CPU 内存 磁盘 网卡 显卡 ... │
└────────────────────────────────────┘
操作系统的双重角色:
1. 资源管理器(Resource Manager)
- 分配CPU时间
- 管理内存空间
- 调度I/O设备
- 协调多进程
2. 抽象层(Abstraction Layer)
- 隐藏硬件复杂性
- 提供统一接口
- 简化应用开发
- 保证程序可移植性1.2 操作系统的核心功能
┌─────────────────────────────────────────────────────────────┐
│ 操作系统的六大核心子系统 │
└─────────────────────────────────────────────────────────────┘
1. 进程管理(Process Management)
┌────────────────────────────────────┐
│ • 进程创建/销毁/调度 │
│ • 线程管理 │
│ • 进程间通信(IPC) │
│ • 进程同步与互斥 │
│ • 死锁处理 │
└────────────────────────────────────┘
2. 内存管理(Memory Management)
┌────────────────────────────────────┐
│ • 虚拟内存 │
│ • 分页与分段 │
│ • 内存分配与回收 │
│ • 页面置换算法 │
│ • 内存保护 │
└────────────────────────────────────┘
3. 文件系统(File System)
┌────────────────────────────────────┐
│ • 文件组织与管理 │
│ • 目录结构 │
│ • 磁盘空间管理 │
│ • 文件权限控制 │
│ • 缓冲与缓存 │
└────────────────────────────────────┘
4. 设备管理(Device Management)
┌────────────────────────────────────┐
│ • 设备驱动程序 │
│ • I/O调度 │
│ • 缓冲区管理 │
│ • 中断处理 │
│ • DMA控制 │
└────────────────────────────────────┘
5. 网络管理(Network Management)
┌────────────────────────────────────┐
│ • 协议栈实现(TCP/IP) │
│ • Socket接口 │
│ • 路由与转发 │
│ • 防火墙规则 │
│ • 网络安全 │
└────────────────────────────────────┘
6. 安全管理(Security Management)
┌────────────────────────────────────┐
│ • 用户认证 │
│ • 访问控制(ACL) │
│ • 审计日志 │
│ • 加密与密钥管理 │
│ • 安全策略执行 │
└────────────────────────────────────┘2. 操作系统架构类型
2.1 宏内核架构(Monolithic Kernel)
┌─────────────────────────────────────────────────────────────┐
│ 宏内核架构(Linux/Unix) │
└─────────────────────────────────────────────────────────────┘
用户空间(User Space)
┌───────────────────────────────────────────────────────────┐
│ 应用程序A 应用程序B 应用程序C 应用程序D │
│ (浏览器) (编辑器) (数据库) (游戏) │
└───────┬───────────┬───────────┬───────────┬───────────────┘
│ │ │ │
└───────────┴───────────┴───────────┘
│
系统调用接口
(System Call Interface)
│
════════════════════▼════════════════════════════════════════
特权模式
内核空间(Kernel Space) (Ring 0)
┌───────────────────────────────────────────────────────────┐
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │进程调度器│ │内存管理器│ │文件系统 │ │网络协议 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬────┘ │
│ │ │ │ │ │
│ ┌────▼─────────────▼─────────────▼─────────────▼────┐ │
│ │ 内核核心(Kernel Core) │ │
│ │ 所有功能运行在同一地址空间 │ │
│ └────┬──────────────────────────────────────────────┘ │
│ │ │
│ ┌────▼──────────────────────────────────────────────┐ │
│ │ 设备驱动程序 │ │
│ │ 磁盘驱动 网卡驱动 显卡驱动 USB驱动 ... │ │
│ └────┬──────────────────────────────────────────────┘ │
│ │ │
└───────┼───────────────────────────────────────────────────┘
│
┌───▼──────────────────────────┐
│ 硬件层(Hardware) │
│ CPU RAM Disk NIC ... │
└──────────────────────────────┘
优点:
✓ 性能高效(组件间直接调用,无需IPC)
✓ 组件紧密集成
✓ 资源共享便捷
✓ 开发相对简单
缺点:
✗ 稳定性差(一个模块崩溃可能导致整个系统崩溃)
✗ 难以维护(代码耦合度高)
✗ 安全风险大(所有代码运行在内核态)
✗ 可扩展性弱
代表系统:Linux、Unix、BSD、早期Windows2.2 微内核架构(Microkernel)
┌─────────────────────────────────────────────────────────────┐
│ 微内核架构(Minix/QNX/seL4) │
└─────────────────────────────────────────────────────────────┘
用户空间(User Space)
┌───────────────────────────────────────────────────────────┐
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │应用程序A │ │应用程序B │ │应用程序C │ │应用程序D │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ └─────────────┴─────────────┴─────────────┘ │
│ │ │
│ ┌──────────────┴──────────────┐ │
│ │ │ │
│ ┌────▼──────┐ ┌──────────┐ ┌────▼────┐ ┌─────────┐ │
│ │文件系统 │ │设备驱动 │ │网络协议 │ │GUI服务 │ │
│ │服务器 │ │服务器 │ │栈服务器 │ │服务器 │ │
│ └────┬──────┘ └────┬─────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │ │
│ └──────────────┴──────────────┴────────────┘ │
│ │ IPC消息传递 │
└──────────────────────┼────────────────────────────────────┘
════════════════════════▼═════════════════════════════════════
特权模式
内核空间(Kernel Space - 极简) (Ring 0)
┌───────────────────────────────────────────────────────────┐
│ 微内核(Microkernel) │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 最小化内核功能 │ │
│ │ │ │
│ │ 1. 进程间通信(IPC) ← 核心功能 │ │
│ │ 2. 基本调度 │ │
│ │ 3. 地址空间管理 │ │
│ │ 4. 线程管理 │ │
│ │ │ │
│ │ 代码量:~10,000行(vs 宏内核的数百万行) │ │
│ └─────────────────────────────────────────────────┘ │
│ │
└───────────────────────┬───────────────────────────────────┘
│
┌───▼──────┐
│ 硬件 │
└──────────┘
优点:
✓ 稳定性高(服务崩溃不影响内核)
✓ 安全性好(权限隔离)
✓ 可维护性强(模块独立)
✓ 易于扩展和移植
✓ 适合嵌入式和关键系统
缺点:
✗ 性能开销大(频繁IPC和上下文切换)
✗ 实现复杂
✗ 调试困难
代表系统:Minix、QNX、seL4、L4、Fuchsia2.3 混合内核架构(Hybrid Kernel)
┌─────────────────────────────────────────────────────────────┐
│ 混合内核架构(Windows NT/macOS XNU) │
└─────────────────────────────────────────────────────────────┘
用户空间(User Space)
┌───────────────────────────────────────────────────────────┐
│ 应用程序 DLL库 用户态服务进程 子系统(Win32/POSIX) │
└───────────────────────┬───────────────────────────────────┘
│
系统调用 / Native API
│
════════════════════════▼════════════════════════════════════
内核空间(Kernel Space)
┌───────────────────────────────────────────────────────────┐
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ 执行体(Executive) │ │
│ │ │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌───────┐ │ │
│ │ │I/O管理 │ │对象管理│ │进程管理│ │内存 │ │ │
│ │ │器 │ │器 │ │器 │ │管理器 │ │ │
│ │ └────────┘ └────────┘ └────────┘ └───────┘ │ │
│ │ │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌───────┐ │ │
│ │ │安全 │ │缓存 │ │电源 │ │配置 │ │ │
│ │ │子系统 │ │管理器 │ │管理器 │ │管理器 │ │ │
│ │ └────────┘ └────────┘ └────────┘ └───────┘ │ │
│ └──────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌──────────────────▼───────────────────────────────┐ │
│ │ 内核层(Kernel) │ │
│ │ - 线程调度 │ │
│ │ - 中断/异常分发 │ │
│ │ - 同步机制(锁/信号量) │ │
│ └──────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌──────────────────▼───────────────────────────────┐ │
│ │ 硬件抽象层(HAL - Hardware Abstraction Layer) │ │
│ │ 隔离硬件差异,提供统一接口 │ │
│ └──────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌──────────────────▼───────────────────────────────┐ │
│ │ 设备驱动程序 │ │
│ └──────────────────┬───────────────────────────────┘ │
│ │ │
└─────────────────────┼─────────────────────────────────────┘
│
┌───▼────┐
│ 硬件 │
└────────┘
特点:
• 结合宏内核的性能和微内核的模块化
• 关键服务在内核态(性能)
• 部分服务在用户态(隔离)
• HAL实现硬件抽象
代表系统:
- Windows NT系列(Windows 10/11/Server)
- macOS(XNU = Mach微内核 + BSD)
- DragonFly BSD3. 用户态与内核态
3.1 特权级别与保护环
┌─────────────────────────────────────────────────────────────┐
│ CPU保护环(Protection Rings - x86架构) │
└─────────────────────────────────────────────────────────────┘
┌─────────┐
│ Ring 3 │ 用户态(User Mode)
│ 应用程序 │ - 受限指令集
│ │ - 有限内存访问
└────┬────┘ - 无硬件访问
│
┌────▼────┐
│ Ring 2 │ 未充分使用
│ 设备驱动 │ (现代OS几乎不用)
│ (可选) │
└────┬────┘
│
┌────▼────┐
│ Ring 1 │ 未充分使用
│ 设备驱动 │ (现代OS几乎不用)
│ (可选) │
└────┬────┘
│
┌────▼────┐
│ Ring 0 │ 内核态(Kernel Mode)
│ 内核 │ - 完整指令集
│ │ - 直接硬件访问
└─────────┘ - 全部内存访问
现代操作系统使用的保护级别:
┌────────────────────────────────────────┐
│ Linux/Unix: │
│ Ring 0: 内核 │
│ Ring 3: 用户程序 │
│ │
│ Windows: │
│ Ring 0: 内核 + 驱动 │
│ Ring 3: 用户程序 │
│ │
│ 虚拟化环境(Intel VT-x/AMD-V): │
│ Ring -1: Hypervisor (VMM) │
│ Ring 0: Guest OS内核 │
│ Ring 3: Guest OS应用 │
└────────────────────────────────────────┘3.2 态切换机制
┌─────────────────────────────────────────────────────────────┐
│ 用户态与内核态切换(Mode Switch) │
└─────────────────────────────────────────────────────────────┘
完整系统调用流程:
用户程序 内核
│ │
│ 1. 调用库函数 │
│ read(fd, buf, size) │
│ │
│ 2. 准备系统调用参数 │
│ - 系统调用号 → EAX │
│ - 参数 → EBX, ECX, EDX │
│ │
│ 3. 触发软件中断 │
├──── int 0x80 (x86)───────────┤
│ 或 syscall (x86-64) │
│ │
│ 4. 保存上下文
│ ├─ 保存用户态寄存器
│ ├─ 切换到内核栈
│ └─ 切换到内核页表
│ │
│ 5. 处理系统调用
│ ├─ 查找系统调用表
│ ├─ 执行对应内核函数
│ └─ sys_read()
│ │
│ 6. 恢复上下文
│ ├─ 将返回值放入EAX
│ ├─ 恢复用户态寄存器
│ └─ 切换回用户页表
│ │
│ 7. 返回用户态 │
├──────── iret/sysret ◀────────┤
│ │
│ 8. 获取返回值 │
│ result = EAX │
│ │
▼ ▼
态切换的性能开销:
┌──────────────────────────────────────┐
│ 操作 时间(周期) │
├──────────────────────────────────────┤
│ 普通函数调用 ~5 cycles │
│ 系统调用(syscall) ~70 cycles │
│ 上下文切换 ~1500 cycles │
│ 进程切换 ~10000 cycles │
└──────────────────────────────────────┘
优化技术:
- vDSO(Virtual Dynamic Shared Object)
某些系统调用在用户态直接执行(如gettimeofday)
- 快速系统调用指令(sysenter/sysexit、syscall/sysret)
减少软件中断开销4. 系统调用机制
4.1 系统调用接口
┌─────────────────────────────────────────────────────────────┐
│ 系统调用层次结构 │
└─────────────────────────────────────────────────────────────┘
应用程序代码
┌──────────────────────────────────────┐
│ int fd = open("/tmp/file", O_RDWR); │ C标准库函数
│ write(fd, data, size); │
│ close(fd); │
└────────────────┬─────────────────────┘
│
┌────────▼─────────┐
│ C标准库 │ 用户态封装
│ (glibc) │
│ - 参数检查 │
│ - 参数传递 │
│ - 调用包装 │
└────────┬─────────┘
│
系统调用接口(syscall)
│
═════════════════▼══════════════════════ 特权级别切换
┌────────────────┐
│ 系统调用表 │ 内核态
│ (sys_call_ │
│ _table) │
└────┬───────────┘
│
┌────────┼────────┬──────────┐
│ │ │ │
┌───▼───┐┌───▼───┐┌──▼────┐┌────▼────┐
│sys_ ││sys_ ││sys_ ││sys_ │
│open ││read ││write ││close │
└───┬───┘└───┬───┘└──┬────┘└────┬────┘
│ │ │ │
└────────┴───────┴──────────┘
│
┌────▼────────┐
│ VFS层 │ 虚拟文件系统
│ (通用接口) │
└────┬────────┘
│
┌────────┼────────┐
│ │ │
┌───▼───┐┌──▼────┐┌──▼────┐
│ext4 ││NTFS ││NFS │ 具体文件系统
└───────┘└───────┘└───────┘4.2 常用系统调用分类
bash
#!/bin/bash
# 展示Linux系统调用分类
cat << 'EOF'
┌─────────────────────────────────────────────────────────────┐
│ Linux系统调用分类(共300+个) │
└─────────────────────────────────────────────────────────────┘
1. 进程控制(Process Control)
┌─────────────────────────────────────┐
│ fork() - 创建子进程 │
│ execve() - 执行程序 │
│ exit() - 终止进程 │
│ wait() - 等待子进程 │
│ getpid() - 获取进程ID │
│ kill() - 发送信号 │
│ clone() - 创建线程 │
└─────────────────────────────────────┘
2. 文件操作(File Operations)
┌─────────────────────────────────────┐
│ open() - 打开文件 │
│ read() - 读取文件 │
│ write() - 写入文件 │
│ close() - 关闭文件 │
│ lseek() - 移动文件指针 │
│ stat() - 获取文件信息 │
│ chmod() - 修改文件权限 │
│ unlink() - 删除文件 │
└─────────────────────────────────────┘
3. 目录操作(Directory Operations)
┌─────────────────────────────────────┐
│ mkdir() - 创建目录 │
│ rmdir() - 删除目录 │
│ chdir() - 改变当前目录 │
│ getcwd() - 获取当前目录 │
│ readdir() - 读取目录项 │
└─────────────────────────────────────┘
4. 内存管理(Memory Management)
┌─────────────────────────────────────┐
│ brk() - 改变数据段大小 │
│ mmap() - 内存映射 │
│ munmap() - 解除映射 │
│ mprotect() - 设置内存保护 │
│ madvise() - 内存使用建议 │
└─────────────────────────────────────┘
5. 进程间通信(IPC)
┌─────────────────────────────────────┐
│ pipe() - 创建管道 │
│ msgget() - 消息队列 │
│ semget() - 信号量 │
│ shmget() - 共享内存 │
│ socket() - 网络套接字 │
└─────────────────────────────────────┘
6. 网络操作(Network Operations)
┌─────────────────────────────────────┐
│ socket() - 创建套接字 │
│ bind() - 绑定地址 │
│ listen() - 监听连接 │
│ accept() - 接受连接 │
│ connect() - 建立连接 │
│ send/recv() - 发送/接收数据 │
└─────────────────────────────────────┘
7. 时间操作(Time Operations)
┌─────────────────────────────────────┐
│ time() - 获取时间 │
│ gettimeofday() - 获取详细时间 │
│ clock_gettime() - 高精度时间 │
│ nanosleep() - 纳秒级睡眠 │
│ alarm() - 设置闹钟 │
└─────────────────────────────────────┘
8. 信号处理(Signal Handling)
┌─────────────────────────────────────┐
│ signal() - 设置信号处理 │
│ sigaction() - 高级信号处理 │
│ kill() - 发送信号 │
│ sigprocmask() - 信号屏蔽 │
└─────────────────────────────────────┘
EOF4.3 系统调用实例
c
/*
* 系统调用示例:文件I/O操作
* 编译:gcc -o syscall_demo syscall_demo.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
void demonstrate_file_operations() {
printf("=== 文件系统调用示例 ===\n");
const char *filename = "/tmp/syscall_test.txt";
const char *data = "Hello, System Call!\n";
char buffer[100];
// 1. open() - 打开/创建文件
printf("\n1. open() 系统调用\n");
int fd = open(filename, O_CREAT | O_RDWR | O_TRUNC, 0644);
if (fd < 0) {
perror("open");
return;
}
printf(" 文件描述符: %d\n", fd);
// 2. write() - 写入数据
printf("\n2. write() 系统调用\n");
ssize_t bytes_written = write(fd, data, strlen(data));
printf(" 写入字节数: %zd\n", bytes_written);
// 3. lseek() - 移动文件指针
printf("\n3. lseek() 系统调用\n");
off_t offset = lseek(fd, 0, SEEK_SET);
printf(" 文件指针位置: %ld\n", (long)offset);
// 4. read() - 读取数据
printf("\n4. read() 系统调用\n");
ssize_t bytes_read = read(fd, buffer, sizeof(buffer) - 1);
buffer[bytes_read] = '\0';
printf(" 读取字节数: %zd\n", bytes_read);
printf(" 读取内容: %s", buffer);
// 5. stat() - 获取文件信息
printf("\n5. stat() 系统调用\n");
struct stat file_stat;
if (fstat(fd, &file_stat) == 0) {
printf(" 文件大小: %ld 字节\n", (long)file_stat.st_size);
printf(" inode号: %ld\n", (long)file_stat.st_ino);
printf(" 权限: %o\n", file_stat.st_mode & 0777);
}
// 6. close() - 关闭文件
printf("\n6. close() 系统调用\n");
close(fd);
printf(" 文件已关闭\n");
// 7. unlink() - 删除文件
printf("\n7. unlink() 系统调用\n");
unlink(filename);
printf(" 文件已删除\n");
}
void demonstrate_process_operations() {
printf("\n\n=== 进程系统调用示例 ===\n");
// 1. getpid() - 获取进程ID
printf("\n1. getpid() 系统调用\n");
pid_t pid = getpid();
pid_t ppid = getppid();
printf(" 当前进程PID: %d\n", pid);
printf(" 父进程PPID: %d\n", ppid);
// 2. fork() - 创建子进程
printf("\n2. fork() 系统调用\n");
pid_t child_pid = fork();
if (child_pid < 0) {
perror("fork");
return;
} else if (child_pid == 0) {
// 子进程
printf(" 子进程: PID=%d, 父PID=%d\n", getpid(), getppid());
exit(0);
} else {
// 父进程
printf(" 父进程: PID=%d, 创建子进程=%d\n", getpid(), child_pid);
// 3. wait() - 等待子进程
int status;
wait(&status);
printf(" 子进程已退出,状态码: %d\n", WEXITSTATUS(status));
}
}
void demonstrate_memory_operations() {
printf("\n\n=== 内存系统调用示例 ===\n");
// 1. brk/sbrk - 调整堆大小(malloc内部使用)
printf("\n1. brk()/sbrk() 系统调用\n");
void *current_brk = sbrk(0);
printf(" 当前堆顶: %p\n", current_brk);
// 2. mmap() - 内存映射
printf("\n2. mmap() 系统调用\n");
size_t size = 4096; // 一页
void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED) {
perror("mmap");
return;
}
printf(" 映射地址: %p\n", addr);
printf(" 映射大小: %zu 字节\n", size);
// 使用映射的内存
char *mapped_data = (char *)addr;
strcpy(mapped_data, "Mapped memory data");
printf(" 写入数据: %s\n", mapped_data);
// 3. munmap() - 解除映射
printf("\n3. munmap() 系统调用\n");
munmap(addr, size);
printf(" 内存映射已解除\n");
}
int main() {
printf("操作系统系统调用演示\n");
printf("===================================\n");
demonstrate_file_operations();
demonstrate_process_operations();
demonstrate_memory_operations();
return 0;
}4.4 追踪系统调用
bash
#!/bin/bash
# 使用strace追踪系统调用
echo "=== 使用strace追踪系统调用 ==="
# 1. 追踪简单命令的所有系统调用
echo -e "\n1. 追踪ls命令"
strace -c ls > /dev/null 2>&1
# -c 选项显示系统调用统计
# 2. 追踪特定系统调用
echo -e "\n2. 只追踪open相关系统调用"
strace -e trace=open,openat ls 2>&1 | head -10
# 3. 追踪进程并显示时间
echo -e "\n3. 显示系统调用时间"
strace -T -e trace=read,write cat /etc/hostname 2>&1 | head -5
# -T 显示每个系统调用的耗时
# 4. 追踪正在运行的进程
echo -e "\n4. 追踪正在运行的进程"
cat << 'EOF'
# 启动一个后台进程
sleep 100 &
PID=$!
# 追踪该进程
strace -p $PID
# 清理
kill $PID
EOF
# 5. 追踪网络系统调用
echo -e "\n5. 追踪网络相关系统调用"
cat << 'EOF'
strace -e trace=network curl -s https://example.com > /dev/null
EOF
# 6. 保存追踪结果
echo -e "\n6. 保存追踪结果到文件"
cat << 'EOF'
strace -o trace.log -ff ls
# -o 输出到文件
# -ff 追踪fork的子进程,每个进程一个文件
EOF5. 主流操作系统对比
5.1 Linux vs Windows vs macOS
┌─────────────────────────────────────────────────────────────┐
│ 主流操作系统架构对比 │
└─────────────────────────────────────────────────────────────┘
特性对比表:
┌──────────┬─────────────┬─────────────┬─────────────┐
│ 特性 │ Linux │ Windows │ macOS │
├──────────┼─────────────┼─────────────┼─────────────┤
│ 内核类型 │ 宏内核 │ 混合内核 │ 混合内核 │
│ │ (Monolithic)│ (Hybrid) │ (XNU) │
├──────────┼─────────────┼─────────────┼─────────────┤
│ 开源情况 │ 开源(GPL) │ 闭源 │ 部分开源 │
│ │ │ │ (Darwin) │
├──────────┼─────────────┼─────────────┼─────────────┤
│ 开发语言 │ C │ C/C++ │ C/Obj-C │
├──────────┼─────────────┼─────────────┼─────────────┤
│ 文件系统 │ ext4/XFS/ │ NTFS/ │ APFS/ │
│ │ Btrfs │ ReFS │ HFS+ │
├──────────┼─────────────┼─────────────┼─────────────┤
│ 进程调度 │ CFS │ 优先级抢占 │ Mach调度 │
│ │ (O(log n)) │ │ │
├──────────┼─────────────┼─────────────┼─────────────┤
│ 图形系统 │ X11/Wayland │ DirectX │ Quartz │
├──────────┼─────────────┼─────────────┼─────────────┤
│ 包管理 │ apt/yum/ │ 无原生 │ Homebrew │
│ │ pacman │ (Windows │ (第三方) │
│ │ │ Store) │ │
├──────────┼─────────────┼─────────────┼─────────────┤
│ 目标用户 │ 服务器/ │ 桌面/ │ 桌面/ │
│ │ 开发者 │ 企业 │ 创意工作 │
├──────────┼─────────────┼─────────────┼─────────────┤
│ 市场占有 │ 服务器95%+ │ 桌面75%+ │ 桌面15% │
│ │ 桌面3% │ 服务器<5% │ │
└──────────┴─────────────┴─────────────┴─────────────┘
Linux内核架构:
┌───────────────────────────────────┐
│ 用户空间 │
│ 应用程序 | glibc | Shell | ... │
└───────────────┬───────────────────┘
│ 系统调用
┌───────────────▼───────────────────┐
│ Linux内核(单一地址空间) │
│ ┌─────────────────────────────┐ │
│ │ 进程调度 | VFS | 内存管理 │ │
│ │ 网络协议栈 | 驱动框架 │ │
│ └─────────────────────────────┘ │
└───────────────┬───────────────────┘
│
┌───▼────┐
│ 硬件 │
└────────┘
Windows NT架构:
┌───────────────────────────────────┐
│ 用户模式 │
│ 应用 | Win32 | POSIX子系统 | ...│
└───────────────┬───────────────────┘
│ Native API
┌───────────────▼───────────────────┐
│ 内核模式 │
│ ┌─────────────────────────────┐ │
│ │ 执行体(I/O管理器等) │ │
│ ├─────────────────────────────┤ │
│ │ 内核(调度/同步) │ │
│ ├─────────────────────────────┤ │
│ │ HAL(硬件抽象层) │ │
│ └─────────────────────────────┘ │
└───────────────┬───────────────────┘
│
┌───▼────┐
│ 硬件 │
└────────┘
macOS XNU架构:
┌───────────────────────────────────┐
│ 用户空间 │
│ Cocoa应用 | BSD工具 | POSIX API │
└───────────────┬───────────────────┘
│
┌───────────────▼───────────────────┐
│ XNU内核(Mach + BSD) │
│ ┌─────────────────────────────┐ │
│ │ BSD层(POSIX、网络、VFS) │ │
│ ├─────────────────────────────┤ │
│ │ Mach微内核(IPC、线程、VM) │ │
│ └─────────────────────────────┘ │
└───────────────┬───────────────────┘
│
┌───▼────┐
│ 硬件 │
└────────┘6. 操作系统演进史
┌─────────────────────────────────────────────────────────────┐
│ 操作系统发展时间线 │
└─────────────────────────────────────────────────────────────┘
1950s - 批处理系统(Batch Processing)
┌──────────────────────────────────┐
│ • 无操作系统 │
│ • 程序员直接操作硬件 │
│ • 手动加载纸带/卡片 │
└──────────────────────────────────┘
1960s - 多道程序系统(Multiprogramming)
┌──────────────────────────────────┐
│ • CTSS (1961) - MIT │
│ • Multics (1964) - 多任务 │
│ • 分时系统出现 │
│ • 中断机制 │
└──────────────────────────────────┘
1970s - UNIX诞生与发展
┌──────────────────────────────────┐
│ • UNIX (1969) - Bell Labs │
│ • C语言重写(1973) │
│ • BSD发布(1977) │
│ • 管道、shell、文件系统 │
└──────────────────────────────────┘
1980s - 个人电脑时代
┌──────────────────────────────────┐
│ • MS-DOS (1981) │
│ • System V (1983) │
│ • Mac OS (1984) │
│ • Windows 1.0 (1985) │
│ • Minix (1987) - 教学用 │
└──────────────────────────────────┘
1990s - 现代操作系统成熟
┌──────────────────────────────────┐
│ • Linux 0.01 (1991) │
│ • Windows NT (1993) │
│ • FreeBSD (1993) │
│ • Windows 95 (1995) │
│ • Mac OS X Server (1999) │
└──────────────────────────────────┘
2000s - 服务器与移动时代
┌──────────────────────────────────┐
│ • Mac OS X (2001) │
│ • Windows XP (2001) │
│ • Android (2008) │
│ • iOS (2007) │
│ • Chrome OS (2009) │
└──────────────────────────────────┘
2010s - 云原生与容器化
┌──────────────────────────────────┐
│ • Docker流行(2013) │
│ • Kubernetes (2014) │
│ • Windows 10 (2015) │
│ • eBPF进入主线(2014) │
│ • WSL (2016) │
└──────────────────────────────────┘
2020s - 新一代操作系统
┌──────────────────────────────────┐
│ • Rust OS项目 │
│ • Fuchsia (Google) │
│ • 形式验证内核(seL4) │
│ • WebAssembly运行时 │
│ • Unikernel │
└──────────────────────────────────┘7. 实战:分析系统启动过程
bash
#!/bin/bash
# 分析Linux系统启动过程
cat << 'EOF'
┌─────────────────────────────────────────────────────────────┐
│ Linux系统启动流程(Boot Process) │
└─────────────────────────────────────────────────────────────┘
1. BIOS/UEFI阶段
┌────────────────────────────────────┐
│ • 加电自检(POST) │
│ • 检测硬件 │
│ • 读取MBR/GPT │
│ • 加载引导加载器 │
└────────────────────────────────────┘
↓
2. 引导加载器(Bootloader)
┌────────────────────────────────────┐
│ GRUB (Grand Unified Bootloader) │
│ • 显示启动菜单 │
│ • 加载内核到内存 │
│ • 传递内核参数 │
│ • 加载initramfs │
└────────────────────────────────────┘
↓
3. 内核初始化
┌────────────────────────────────────┐
│ • 解压内核 │
│ • 初始化内存管理 │
│ • 初始化进程调度 │
│ • 挂载根文件系统(rootfs) │
│ • 启动init进程(PID 1) │
└────────────────────────────────────┘
↓
4. Init系统(systemd/SysV)
┌────────────────────────────────────┐
│ systemd (现代Linux) │
│ • 并行启动服务 │
│ • 加载target配置 │
│ • 启动系统服务 │
│ • 挂载文件系统 │
└────────────────────────────────────┘
↓
5. 运行级别/Target
┌────────────────────────────────────┐
│ • multi-user.target(文本模式) │
│ • graphical.target(图形界面) │
│ • 启动网络服务 │
│ • 启动登录管理器 │
└────────────────────────────────────┘
↓
6. 用户登录
┌────────────────────────────────────┐
│ • 显示登录提示 │
│ • 认证用户 │
│ • 启动Shell │
│ • 加载用户环境 │
└────────────────────────────────────┘
EOF
echo "=== 查看系统启动信息 ==="
# 1. 查看内核启动信息
echo -e "\n1. 内核启动日志(dmesg)"
dmesg | head -20
# 2. 查看systemd启动时间
echo -e "\n2. 系统启动时间分析"
systemd-analyze
# 3. 查看各服务启动时间
echo -e "\n3. 服务启动时间排序"
systemd-analyze blame | head -10
# 4. 生成启动流程图(需要安装graphviz)
echo -e "\n4. 生成启动流程图"
cat << 'SCRIPT'
systemd-analyze plot > boot.svg
# 在浏览器中打开boot.svg查看
SCRIPT
# 5. 查看关键启动单元
echo -e "\n5. 关键启动单元"
systemctl list-dependencies graphical.target | head -20
# 6. 查看启动失败的服务
echo -e "\n6. 检查失败的服务"
systemctl --failed8. 延伸阅读与学习资源
8.1 推荐书籍
经典教材:
- 《操作系统概念》(恐龙书)- Silberschatz
- 《现代操作系统》- Andrew S. Tanenbaum
- 《深入理解计算机系统》(CSAPP)
- 《操作系统设计与实现》- Tanenbaum
Linux内核:
- 《深入理解Linux内核》
- 《Linux内核设计与实现》
- 《Linux设备驱动程序》
Windows内核:
- 《Windows内核原理与实现》
- 《Windows Internals》
8.2 在线资源
bash
# 经典操作系统课程
MIT 6.828: Operating System Engineering
https://pdos.csail.mit.edu/6.828/
UC Berkeley CS162: Operating Systems
https://cs162.org/
# 实践项目
xv6操作系统(MIT教学OS)
https://github.com/mit-pdos/xv6-public
Linux内核源码
https://kernel.org/
# 社区资源
LWN.net - Linux Weekly News
https://lwn.net/
OSDev Wiki
https://wiki.osdev.org/8.3 关键概念总结
┌─────────────────────────────────────────────────────────────┐
│ 操作系统核心概念图谱 │
└─────────────────────────────────────────────────────────────┘
操作系统
├── 架构类型
│ ├── 宏内核(Linux/Unix)- 高性能,低隔离
│ ├── 微内核(Minix/QNX)- 高隔离,低性能
│ └── 混合内核(Windows/macOS)- 平衡方案
│
├── 特权级别
│ ├── 用户态(Ring 3)- 受限执行
│ ├── 内核态(Ring 0)- 完全控制
│ └── 态切换机制 - 系统调用/中断/异常
│
├── 系统调用
│ ├── 接口层 - C库封装
│ ├── 切换机制 - int 0x80/syscall
│ ├── 调用表 - 内核函数索引
│ └── 分类 - 进程/文件/内存/网络
│
├── 核心功能
│ ├── 进程管理 - 调度/IPC/同步
│ ├── 内存管理 - 虚拟内存/分页
│ ├── 文件系统 - VFS/ext4/NTFS
│ ├── 设备管理 - 驱动/中断
│ ├── 网络协议 - TCP/IP栈
│ └── 安全机制 - 权限/隔离
│
└── 演进趋势
├── 容器化 - 轻量级虚拟化
├── eBPF - 内核可编程性
├── Rust OS - 内存安全
└── 形式验证 - 正确性保证9. 实验项目
项目1:编写一个最小系统调用
c
/*
* 为Linux内核添加一个简单的系统调用
* 功能:返回系统调用次数
*/
// 1. 在内核源码中添加系统调用实现
// kernel/sys.c
SYSCALL_DEFINE0(hello)
{
printk(KERN_INFO "Hello from kernel!\n");
return 0;
}
// 2. 在系统调用表中注册
// arch/x86/entry/syscalls/syscall_64.tbl
// 548 common hello sys_hello
// 3. 在头文件中声明
// include/linux/syscalls.h
asmlinkage long sys_hello(void);
// 4. 用户空间调用
// test_syscall.c
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#define SYS_hello 548
int main() {
long result = syscall(SYS_hello);
printf("System call returned: %ld\n", result);
return 0;
}项目2:追踪系统调用性能
python
#!/usr/bin/env python3
"""
使用eBPF追踪系统调用性能
需要安装:pip install bcc
"""
from bcc import BPF
import time
# eBPF程序
bpf_program = """
#include <uapi/linux/ptrace.h>
struct data_t {
u64 ts;
u64 delta;
u32 pid;
char comm[TASK_COMM_LEN];
};
BPF_HASH(start, u32);
BPF_PERF_OUTPUT(events);
int trace_entry(struct pt_regs *ctx) {
u32 pid = bpf_get_current_pid_tgid();
u64 ts = bpf_ktime_get_ns();
start.update(&pid, &ts);
return 0;
}
int trace_return(struct pt_regs *ctx) {
u32 pid = bpf_get_current_pid_tgid();
u64 *tsp = start.lookup(&pid);
if (tsp != 0) {
u64 delta = bpf_ktime_get_ns() - *tsp;
struct data_t data = {};
data.ts = *tsp;
data.delta = delta;
data.pid = pid;
bpf_get_current_comm(&data.comm, sizeof(data.comm));
events.perf_submit(ctx, &data, sizeof(data));
start.delete(&pid);
}
return 0;
}
"""
# 加载eBPF程序
b = BPF(text=bpf_program)
# 附加到open系统调用
b.attach_kprobe(event="sys_open", fn_name="trace_entry")
b.attach_kretprobe(event="sys_open", fn_name="trace_return")
print("追踪open系统调用,按Ctrl+C退出...")
# 处理事件
def print_event(cpu, data, size):
event = b["events"].event(data)
print(f"PID: {event.pid}, 命令: {event.comm.decode()}, "
f"耗时: {event.delta / 1000:.2f} μs")
b["events"].open_perf_buffer(print_event)
while True:
try:
b.perf_buffer_poll()
except KeyboardInterrupt:
break下一步:学习进程管理,深入理解进程调度、IPC和并发控制。
相关模块:
- Computer_Hardware - 理解硬件基础
- Linux - Linux系统实战
- Container - 容器技术原理
文件大小:约33KB 最后更新:2024年
💬 讨论
使用 GitHub 账号登录后即可参与讨论