八股文 / 操作系统速查
操作系统面试速查题库
本页用于学完后的复习与面试表达。第一次学习请从 操作系统系统课 开始,先理解内核状态、资源队列和完整执行路径。
〇、操作系统介绍
1. 什么是操作系统
操作系统是介于硬件资源和应用程序之间的系统软件,能控制和管理计算机系统的硬件和软件资源,调度计算机工作与资源分配,为用户和软件提供服务。
2. 操作系统的特征
- 并发:多个程序同时执行的能力
- 共享:资源可供多个并发进程使用
- 互斥共享:一段时间内仅一个进程访问
- 同时访问:多个进程交替访问
- 虚拟:物理实体转化为逻辑对应物
- 异步:进程以不可预知的速度推进
3. 操作系统的功能
- 资源分配与回收 - 管理CPU、内存、硬盘、I/O设备
- 为应用程序提供服务 - 通过系统调用提供统一接口
- 管理应用程序 - 控制进程生命周期
- 内核功能 - 进程调度、内存管理、硬件通信、系统调用
4. 操作系统的角色
- 管理者:CPU、内存、外存、I/O管理
- 魔术师:使每个进程感觉独占资源
5. 用户程序与操作系统的关系
相互调用的关系——操作系统启动后管理所有进程,进程调用操作系统服务实现功能。
一、进程与线程
1. 进程和线程的区别
简要回答:
- 进程:计算机中一个执行的程序实例,是操作系统资源分配的最小单位
- 线程:比进程更小的概念,也称”轻量级进程”,一个进程可拥有多个线程
| 维度 | 进程 | 线程 |
|---|---|---|
| 调度单位 | 在引入线程前是调度最小单位 | 引入内核级线程后是调度最小单位 |
| 资源分配 | 资源分配最小单位 | 拥有少量资源 |
| 并发性 | 多进程可并发执行 | 多线程可并发执行 |
| 独立性 | 默认不共享全局变量,独立地址空间 | 共享大部分资源 |
| 系统开销 | 通信和切换开销大 | 通信和切换开销小 |
| 多处理机 | 单进程只运行在一个处理机 | 多线程进程可充分利用多处理机 |
详细回答:
进程具有四个主要特点:动态性、并发性、独立性和异步性。引入线程的优势包括进一步提高并发性、共享地址空间、更轻量级,以及提升交互性。
线程实现方式:
- 用户级线程:应用程序实现管理,操作系统感知不到
- 内核级线程:由操作系统内核支持,线程是系统调度最小单位
2. 进程间通信方式
- 信号量机制 - 通过P/V操作控制资源访问,解决同步互斥问题
- 共享存储机制 - 允许多个进程直接访问同一块内存区域,传输高效
- 消息传递机制 - 需要内核支持,通过消息队列传递数据块
- 管道通信机制 - 分为匿名管道(父子进程)和命名管道(无关进程)
- 套接字机制 - 网络通信方式,支持不同主机间进程通信
详细说明:
- 信号量:同步通信机制,支持P()和V()原子操作
- 共享存储:细分为共享数据结构和共享存储区两种方式
- 消息传递:包括直接通信和间接通信(信箱模式)
- 管道:匿名管道常用于亲缘进程,命名管道可用于无亲缘进程;它是内核维护的字节流,容量和原子写入边界依操作系统实现与配置,不能固定理解为 4KB
- Socket:支持TCP(面向连接)或UDP(无连接)
3. 进程调度算法
七大调度算法:
- 先来先服务(FCFS) - 非抢占式,按到达顺序执行。优点:简单公平;缺点:长作业阻塞短作业
- 短进程优先(SPF/SRT) - SPF(非抢占)vs SRT(抢占式),优化平均等待时间,问题:长作业可能饥饿
- 优先级调度(PSA) - 根据优先级分配处理器,适用:实时系统,风险:低优先级进程饥饿
- 高响应比优先(HRRN) - 响应比 = (等待时间 + 运行时间) / 运行时间,兼顾公平性与效率
- 时间片轮转(RR) - 每个进程分配等量时间片,适用:交互式系统
- 多级队列调度 - 多个队列采用不同算法,可根据任务类型定制策略
- 多级反馈队列调度 - 现代操作系统标准方案,新进程从最高优先级开始,逐级降级
| 算法 | 特性 | 优点 | 缺点 |
|---|---|---|---|
| FCFS | 非抢占 | 简单公平 | 可能convoy效应 |
| SJF | 非抢占 | 最小平均等待 | 可能饿死长作业 |
| RR | 抢占 | 公平性好 | 上下文切换开销 |
| 优先级 | 可选 | 支持优先级区分 | 可能低优先级饿死 |
| MLFQ | 抢占 | 自适应调度 | 实现复杂 |
4. 作业调度、内存调度、进程调度的区别
- 作业调度(高级调度/长程调度):从后备队列中选择作业调入内存并创建进程,调度频率低(分钟到小时级),控制系统并发度
- 内存调度(中级调度/中程调度):在内存紧张时将部分进程交换到外存,调度频率中等(秒到分钟级)
- 进程调度(低级调度/短程调度):从就绪队列选择进程执行,调度频率极高(毫秒级)
二、CPU状态与模式
1. 处理机的两种状态
- 核心态(Kernel Mode):CPU执行操作系统内核代码时的工作状态,可执行所有指令、访问所有内存、直接操作硬件
- 用户态(User Mode):CPU运行用户应用程序时的工作状态,只能执行非特权指令,通过操作系统接口间接完成硬件操作
状态切换途径:
- 系统调用(应用程序主动请求)
- 中断(外部设备请求)
- 异常(程序错误或特殊条件)
模式切换开销:
- 直接开销:保存/恢复寄存器、切换栈指针、更新CPU模式位
- 间接开销:缓存和分支预测状态可能被扰动;TLB 是否失效取决于是否切换地址空间及硬件地址空间标识等机制
2. 用户态和内核态
- 用户态:应用程序在用户空间执行代码时的运行模式,CPU仅能运行部分指令且只能访问用户空间内存
- 内核态:CPU可运行全部指令、访问全部内存空间,具有硬件完全访问权限
- 交互机制:系统调用作为安全接口,触发用户态到内核态的切换
三、中断与异常
1. 什么是中断、异常
中断(Interrupt):
- 由外部硬件设备产生的异步事件信号
- 特性:异步、可屏蔽、可嵌套
- 分类:硬件中断(可屏蔽INTR和非屏蔽NMI)、软件中断(INT指令触发)
异常(Exception):
- CPU内部执行指令时检测到的同步事件
- 特性:同步、不可屏蔽、精确性
- 分类:故障(缺页异常,可恢复)、陷阱(断点、系统调用)、终止(硬件故障,严重错误)
2. 中断和异常的区别
| 维度 | 异常 | 中断 |
|---|---|---|
| 同步性 | 同步于指令执行 | 异步于当前指令 |
| 来源 | CPU内部 | CPU外部 |
| 返回点 | 因类型而异 | 被中断指令的下一条 |
中断响应阶段(硬件自动完成):
- 关中断,禁止新中断响应
- 保存断点和程序状态字
- 引出中断服务程序
中断处理阶段(软件执行):
- 保护现场(保存通用寄存器)
- 执行中断处理程序
- 恢复现场并开中断
3. 中断处理流程
四个阶段:中断请求 → 中断响应 → 中断处理 → 中断返回
关键步骤:中断源产生 → 中断控制器仲裁 → CPU保存程序计数器和状态字 → 向量表查询 → 执行中断服务程序 → 恢复现场
中断分类: 硬中断(IRQ)、软中断(INT指令)、异常(除零、缺页)、不可屏蔽中断(NMI)
四、同步与互斥
1. 线程的同步方式
内核级线程同步方式:
- 互斥锁(Mutex):确保同一时间只有一个线程进入临界区,Linux的futex优化减少上下文切换
- 信号量(Semaphore):控制资源访问数量,包括计数信号量和二进制信号量
- 条件变量:用于线程间状态通知,需搭配互斥锁使用,典型应用是生产者-消费者模型
- 读写锁:允许多读单写,适合读多写少场景
- 自旋锁:忙等待锁,适用于多核短临界区
用户级线程同步方式:
- 原子操作:通过CAS等原子指令避免锁开销
- 协程同步原语:如Go的channel,通过消息传递替代共享内存
- 轻量级锁:先尝试用户态自旋,失败后升级为内核锁
2. 几种典型的锁
- 互斥锁:保护临界区,确保独占访问,通常与条件变量配合使用
- 读写锁:读锁共享,写锁独占,适合缓存系统、数据库等读多写少场景
- 自旋锁:通过忙等待实现,避免线程切换开销,适用于锁占用时间极短的场景
信号量、锁和条件变量的关系: 信号量是通用同步机制,互斥锁是其特例(二进制信号量)。读写锁和自旋锁不属于信号量特例,是针对不同场景的锁类型。
3. 进程的同步与互斥
同步:多个进程按一定顺序执行,确保数据正确性和一致性 互斥:多个进程不能同时访问共享资源,防止数据竞争
实现方法:
- 软件实现:单标志法、双标志先检查法、双标志后检查法、Peterson算法
- 硬件实现:关中断方法、TSL和Swap指令
- 高级机制:信号量、管程、屏障、条件变量
四条设计准则:
- 空闲让进:无进程在临界区时立即允许进入
- 忙则等待:有进程在用临界资源时其他进程等待
- 有限等待:保证进程在有限时间内进入临界区
- 让权等待:无法进入时释放处理器
五、死锁
1. 什么是死锁及如何避免
定义:多个进程或线程因竞争资源而互相等待,导致无法继续执行的现象
四个必要条件:
- 互斥条件:资源一次仅被一个进程占用
- 请求和保持条件:持有资源的同时请求其他资源
- 不可抢占条件:资源只能由进程主动释放
- 循环等待条件:存在进程的循环等待链
预防方法:
- 破坏互斥条件:允许资源被多个进程共享
- 破坏请求和保持条件:请求资源时必须释放已持有资源
- 破坏不可抢占条件:允许系统抢占已占用资源
- 破坏循环等待条件:对资源排序,按顺序请求
2. 产生死锁的原因
- 资源竞争:多进程争用有限资源
- 推进顺序不当:进程执行顺序不合理
- 资源分配策略问题:缺乏预防和避免机制
- 程序设计缺陷:未考虑资源获取顺序
死锁处理策略: 预防 → 避免(银行家算法)→ 检测(资源分配图检测环路)→ 恢复(终止进程或剥夺资源)
3. 银行家算法
由Dijkstra提出的动态资源分配算法,对于每次资源申请实时判断死锁风险。
数据结构:
- Available[m]:系统各类资源可用数量
- Max[n][m]:进程最大资源需求矩阵
- Allocation[n][m]:当前资源分配矩阵
- Need[n][m]:进程剩余需求 = Max - Allocation
安全性检查: 使用Work向量和Finish数组,寻找满足 Finish[i] == FALSE && Need[i][j] ≤ Work[j] 的进程,依次分配直至所有进程完成或无法继续。
优缺点: 严格避免死锁、资源利用率较高,但需预先声明最大需求、时间复杂度O(n²)。
六、内存管理
1. 虚拟内存
概念:操作系统提供的逻辑扩充内存的方法,为每个进程提供独立连续的地址空间,结合物理内存和磁盘空间扩展可用内存。
核心机制:
- 地址空间隔离:每个进程拥有独立虚拟地址空间(32位系统通常4GB)
- 分页机制:将虚拟内存和物理内存划分为固定大小的页(通常4KB)
- 按需调页:仅在实际访问时才将页面加载到物理内存
- 写时复制:多个进程共享只读页面,写操作时再创建副本
- 内存映射文件:将文件直接映射到进程地址空间
实现方式: 请求分页(固定大小页面)和请求分段(不同大小段落)
2. 内存分段和分页
分段存储管理: 将程序逻辑地址空间划分为多个可变长度的段(代码段、数据段、堆栈段),便于编程但容易产生外部碎片。
分页存储管理: 将物理内存划分为固定大小的页框和页面,通过页表实现地址映射,消除外部碎片但可能产生内部碎片。
| 维度 | 分段 | 分页 |
|---|---|---|
| 地址类型 | 二维(段号+偏移) | 一维(页号+偏移) |
| 碎片类型 | 外部碎片 | 内部碎片 |
| 用户可见性 | 不透明 | 透明 |
现代操作系统主要采用分页机制,结合TLB和MMU硬件支持。
3. 页面置换算法
| 算法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| OPT(最佳置换) | 理论最优,缺页率最低 | 无法实现,需预知未来 | 理论分析参考 |
| FIFO(先进先出) | 实现简单,开销低 | 可能引发Belady异常 | 简单系统 |
| LRU(最近最久未使用) | 性能接近OPT | 实现复杂,开销较高 | 高性能要求系统 |
| LFU(最少使用) | 适合频率差异明显场景 | 对突发模式不敏感 | 访问模式稳定系统 |
| Clock(时钟置换) | 实现简单,性能接近LRU | 引用位判断可能不准确 | 平衡性能和复杂度 |
| 改进Clock | 减少I/O开销 | 实现更复杂 | I/O性能要求高 |
Belady异常:增加内存帧数反而导致缺页率上升,FIFO算法容易出现。
局部性原理:时间局部性(最近访问的可能再次访问)和空间局部性(访问位置附近可能被访问)。
4. 内存连续分配管理方式
- 单一连续分配:内存分为OS和用户程序两部分,同时仅一个用户进程,无碎片但CPU利用率极低
- 固定分区分配:启动时划分为若干固定大小分区,产生内部碎片
- 动态分区分配:不预先划分,按需分配。四种算法:首次适应、最佳适应、最坏适应、邻近适应。长期使用产生外部碎片
七、I/O与设备管理
1. I/O控制方式
- 程序直接控制(轮询) - CPU主动持续检查设备状态,实现简单但CPU利用率极低
- 中断驱动方式 - 设备完成后向CPU发送中断信号,CPU利用率提高
- DMA方式 - DMA控制器接管数据传输,CPU只需初始化,适合高速大批量数据
- 通道控制方式 - 通道作为专用I/O处理器独立执行,有自己的指令系统,CPU几乎完全解放
2. IO模型
5种IO模型:阻塞IO、非阻塞IO、IO多路复用、信号驱动IO、异步IO
核心差异在于等待数据就绪阶段和数据拷贝阶段的处理策略。
| 模型 | 特点 | 适用场景 |
|---|---|---|
| 阻塞IO | 简单但并发差 | 简单客户端、低并发 |
| 非阻塞IO | 需轮询,CPU占用高 | GUI应用、简单游戏服务器 |
| IO多路复用 | 单线程处理多连接 | Nginx、Redis、WebSocket |
| 信号驱动IO | 内核数据就绪时通知 | UDP服务器、嵌入式 |
| 异步IO | 真正异步,用户态不参与 | 高性能文件服务器、数据库 |
同步IO vs 异步IO: 前4种都是同步IO(数据拷贝阶段需进程参与),只有异步IO整个过程进程不需参与。
3. epoll为什么比select/poll高效
- 事件驱动:仅返回就绪的文件描述符,避免遍历所有fd
- 内核回调:通过回调机制通知就绪事件,O(1)时间复杂度
- 共享内存:减少用户空间和内核空间的数据拷贝
- 红黑树存储fd:插入删除为O(log n)
| 特性 | select | poll | epoll |
|---|---|---|---|
| 时间复杂度 | O(n) | O(n) | O(1) |
| 连接数限制 | 1024 | 无 | 无 |
| 内存拷贝 | 每次调用都拷贝 | 每次调用都拷贝 | 内核-用户共享 |
| 触发方式 | 水平触发 | 水平触发 | 支持水平/边缘触发 |
4. 磁盘调度算法
磁盘访问时间 = 寻道时间 + 旋转延迟 + 传输时间
| 算法 | 特点 | 缺陷 | 适用场景 |
|---|---|---|---|
| FCFS | 公平、简单 | 性能最差 | 轻负载、SSD |
| SSTF | 性能好 | 可能饥饿 | 中等负载 |
| SCAN | 无饥饿 | 边缘请求等待长 | 多用户系统 |
| C-SCAN | 等待时间均匀 | 牺牲部分性能 | 实时系统 |
| LOOK | 改进SCAN | 实现较复杂 | 文件服务器 |
| C-LOOK | 改进C-SCAN | 实现较复杂 | 多媒体服务器 |
5. 设备管理的主要功能
- 设备分配:独占分配(打印机)、共享分配(磁盘)、虚拟分配(SPOOLing)
- 设备驱动:统一接口,硬件抽象,驱动模型分类(字符设备、块设备、网络设备)
- 缓冲管理:单缓冲、双缓冲、循环缓冲、缓冲池
- 中断处理:产生中断请求 → 保存现场 → 识别中断源 → 执行中断服务程序 → 恢复现场
- 错误检测与恢复:ECC校验、重传机制、坏块管理
八、其他
1. 用户程序变为可执行程序
四个阶段:
- 预处理 - 展开头文件、宏替换、条件编译
- 编译 - 词法分析 → 语法分析 → 语义分析 → 代码优化 → 代码生成(汇编代码)
- 汇编 - 汇编代码转译为机器指令,生成目标文件
- 链接 - 符号解析 → 地址分配 → 重定位 → 库链接 → 生成可执行文件
静态链接 vs 动态链接: 静态链接将库代码直接复制到可执行文件;动态链接仅包含库引用,运行时加载。
2. 硬链接与软链接的区别
| 维度 | 硬链接 | 软链接(符号链接) |
|---|---|---|
| inode | 共享相同inode | 独立inode |
| 文件系统 | 必须同一文件系统 | 可跨文件系统 |
| 删除原文件 | 仍可访问数据 | 成为悬空链接 |
| 链接目标 | 只能链接文件 | 可链接文件和目录 |
| 存储内容 | 目录项引用inode | 存储目标路径字符串 |
硬链接不能跨文件系统的原因:inode号仅在同一文件系统内唯一,不同文件系统有各自独立的inode编号空间。
来源:卡码笔记