在正式开始操作系统学习前,我犹豫是否要构建一套体系化的学习笔记。然而,当回忆起初次接触操作系统时被庞杂概念"狂轰滥炸"的迷茫经历,决定还是以更轻松的叙事方式描述。
什么是操作系统?
- 功能:统一接口;管理硬件资源,协调应用程序所需资源;管理应用程序,并为应用程序提供服务;
- 硬件抽象:CPU->进程,内存->地址空间,磁盘->文件
- 功能服务:进程管理、线程管理、物理内存管理、虚拟内存管理、文件系统管理、中断处理、I/O设备驱动
- 特征:并发,异步共享,虚拟化 -> 中断、调度、分时、服务
- 目标:根据不同硬件之间的性能差异,权衡效率(公平)、安全、可预测性等
- 组成:shell界面+kernel内核
- 历史:纸带 -> 批处理 -> 多道程序设计 -> 分时 -> 中断 -> 网络(Internet) -> 分布式计算
操作系统启动
- BIOS:基本输入输出系统,用于控制计算机外设,包括主板BIOS、显卡BIOS、网卡BIOS等等,一般存放在ROM中,即使掉电也不会消失
- 内存分配:由于历史原因,一般开头1MB内存比较特殊,
A0000~BFFFF
保留给显存使用,C0000~FFFFF
保留给BIOS使用,其中系统BIOS占后64KB
- 上电:按下电源开关,硬件通电,主板控制芯片组向CPU发送并保持RESET(重置)信号;当稳定供电后撤回信号,CPU从
FFFF0
处执行跳转指令,跳转到系统BIOS的启动代码处。 - POST(加电自检):系统BIOS的启动代码会检测系统中一些关键设备是否存在和能否正常工作,如果发现致命错误,就会控制喇叭发声来报告错误,声音的长短和次数代表了错误类型;之后跳转到其他设备BIOS的启动代码处执行,初始化相关设备;同时,BIOS会将特定信息显示在屏幕上,你还可以按下指定键进入BIOS设置界面,对计算机进行配置。
- Boot Loader(引导加载):从硬盘第一个主引导扇区中读取引导加载程序并执行,负责加载磁盘中的操作系统的核心文件到内存中。
- 操作系统启动:核心文件负责初始化操作系统的各个模块,并将控制权交给操作系统。
- 操作系统初始化:操作系统开始启动并加载系统服务、设备驱动程序等,完成一系列初始化和配置工作,为用户提供操作系统的功能和界面。
异常处理机制
设备和程序交互,存在异常控制流,整个过程透明,异常或持续或等待或杀死或重新执行。
当外设或程序产生异常时,如外设异步中断、程序同步系统调用、程序异步|同步故障|中止,会发送一个异常标记;
处理器检测到有异常事件发生,保存此时上下文,完成用户态->内核态的转换,再根据异常事件类型(异常标记)从异常表中检索到对应的异常处理程序并执行,完成后:
- 将控制权返回异常前正在执行的指令
- 将控制权返回异常前正在执行的下一条指令
- 终止异常前正在执行的程序
最后,清除异常标记,恢复异常前上下文,完成内核态->用户态的转换。
函数调用和系统调用的区别:
- 函数调用早同一段栈空间中完成功能调用和返回;而系统调用存在用户态和内核态之间的切换,属于不同的堆栈。
- 系统调用比函数调用更大开销,需要完成上下文转换。
- 系统调用比函数调用更安全,存在验证参数。
- 系统调用存在异常表及对应编号。
存储分层体系
由于处理器与存储器之间巨大的频率差异,需要大大缩短从存储器中存取数据的时间,利用程序局部性特点,设计了存储器的层次结构,即基于下一层的缓存机制。同时解决了持续性问题。

不同层次之间的逻辑块大小不一样,例如寄存器与L1之间以字为一个块,内存与磁盘之间以页为一个块。
不同存储器采用了不同的存储技术,需要中间件(缓存替换算法、合适的逻辑块大小)保证兼容性,提高缓存命中,降低访存时间。
最终使得整个系统容量大且访问快。
内存管理
抽象出逻辑地址方便编程,地址独立以构建保护机制,地址共享进行数据传递,利用硬盘持久性去虚拟化更多内存地址空间。
地址空间
- 物理地址空间:硬件支持的地址空间
- 逻辑地址空间:一个运行程序所拥有的内存范围,是一种规范化区间,与一段物理地址范围相对应;汇编代码中的地址即逻辑地址
C程序首先通过预处理、编译和汇编生成可重定位目标代码、建立符号表、生成重定位信息,此时生成的地址是相对于本模块的偏移量(从0开始),不是最终地址。
然后通过链接合并多个可重定位目标代码和库文件为可执行文件,完成符号解析与重定位、逻辑地址分配。
可执行文件再通过加载器载入内存,同时操作系统建立映射表、确定该程序拥有地址范围—基址和界限。
最后运行时指令先进行地址安全检查(在基址和界限范围内),再通过CPU的MMU将逻辑地址转换为物理地址,并发送访存请求;否则触发异常。
内存分配
连续分配
连续分配场景:程序代码分配,磁盘数据块分配
内存碎片问题:无法被继续连续分配的内存空间,包括分配单元内外两种碎片
经典分配算法:需要列表记录空闲块位置,需要考虑已释放块合并
- 首次适配:使用检索到的第一个足够大可用空闲块,简单但存在外部碎片。
- 最优适配:使用外部碎片最小的足够大可用空闲块,简单但存在较多微小外部碎片,适合小尺寸块请求分配。
- 最差适配:使用外部碎片最大的足够大可用空闲块,但难以分配较大块请求,适合中等尺寸块请求分配。