#一、操作系统高频笔试题
#141. 进程和线程的区别是什么?
#知识点
- 资源分配单位 vs 调度执行单位
- 地址空间是否共享
- 切换成本
- 崩溃隔离与通信成本
#详细解答
进程是操作系统进行资源分配的基本单位,通常拥有独立的虚拟地址空间、文件描述符表和系统资源;线程是 CPU 调度和执行的基本单位,同一进程内的多个线程共享地址空间和大部分资源,但各自有独立栈和寄存器上下文。
最关键的区别有四点:
- 资源边界:进程彼此隔离,线程共享进程资源。
- 切换成本:线程切换通常比进程切换轻,因为不需要完整切换地址空间。
- 通信方式:进程间通信依赖
IPC,线程间通信更直接,但同步更复杂。 - 稳定性:进程隔离更强,一个线程把共享内存写坏,整个进程都可能崩掉。
一句话总结:进程更强调隔离,线程更强调并发。
#142. 用户态和内核态有什么区别?为什么要区分这两种模式?
#知识点
- CPU 特权级
- 用户程序权限受限
- 内核控制硬件和关键资源
- 系统调用是主要入口
#详细解答
用户态和内核态的本质区别是权限不同。用户态程序不能直接执行特权指令,也不能直接访问硬件和关键内核数据结构;内核态拥有更高权限,可以调度 CPU、管理内存、控制设备和处理中断。
之所以要区分,是为了保证系统安全和稳定。如果普通应用都能直接改页表、关中断、写磁盘控制器,系统会立刻失去边界。
程序通常通过系统调用从用户态进入内核态,例如:
read/writeopenforkmmap
所以用户态/内核态不是抽象概念,而是系统安全边界。
#143. 什么是上下文切换?为什么上下文切换过多会让系统变慢?
#知识点
- 保存和恢复执行现场
- 线程切换 vs 进程切换
- cache / TLB 污染
- 切换本身不做业务计算
#详细解答
上下文切换是 CPU 从一个线程或进程切到另一个执行体时,保存当前执行状态并恢复下一个执行状态的过程。这里的状态包括寄存器、程序计数器、栈指针,进程切换时还可能涉及地址空间相关状态。
它会让系统变慢,主要因为:
- 切换本身不产生业务价值;
- 会破坏 cache 局部性;
- 会降低
TLB命中率; - 线程过多时调度开销显著上升。
因此高并发系统的一个常见误区就是“线程越多越好”,实际上线程太多经常先把系统拖进上下文切换地狱。
#144. 什么是死锁?死锁产生的必要条件有哪些?
#知识点
- 互斥
- 占有并等待
- 不可剥夺
- 循环等待
#详细解答
死锁是多个执行体彼此等待对方持有的资源,最终谁也无法继续执行的状态。经典四个必要条件是:
- 互斥:资源一次只能给一个执行体用;
- 占有并等待:已经拿到一部分资源,还在等别的资源;
- 不可剥夺:资源不能被强行抢走;
- 循环等待:等待关系形成环。
面试里更高分的点在于:只要破坏其中任意一个条件,就能避免死锁。例如统一加锁顺序,本质上是在破坏循环等待。
#145. 什么是虚拟内存?它解决了什么问题?
#知识点
- 虚拟地址与物理地址分离
- 每个进程拥有独立地址空间
- 按页映射
- 提升隔离性与利用率
#详细解答
虚拟内存的核心思想是:程序访问的是虚拟地址,而不是直接访问物理内存。硬件和操作系统负责把虚拟地址翻译成物理地址。
它主要解决三件事:
- 隔离性:每个进程看到自己的独立地址空间;
- 抽象性:程序不用关心自己真实放在物理内存哪里;
- 利用率:可以按需加载和换页,把不活跃页放到后备存储。
所以虚拟内存不是“凭空造更多内存”,而是让内存管理更灵活、更安全。
#146. 什么是分页?页表是做什么的?
#知识点
- 虚拟地址空间切成页
- 物理内存切成页框
- 页表记录映射关系
- 页表项包含权限、存在位、脏位等
#详细解答
分页是虚拟内存的常见实现方式。它把虚拟地址空间切成固定大小的页,把物理内存切成同样大小的页框,再通过页表记录二者映射关系。
页表项通常不只记录地址,还包含:
- 页面是否在内存中;
- 是否可写;
- 是否被访问过;
- 是否被修改过。
面试里要注意强调:分页带来了灵活性,但页表本身也有成本,所以才需要多级页表和 TLB。
#147. 什么是缺页异常(page fault)?为什么缺页会很慢?
#知识点
- 访问的页当前不在物理内存
- 陷入内核
- 可能需要磁盘换入
- IO 远慢于内存访问
#详细解答
当程序访问某个虚拟页时,如果这个页当前没有映射到物理内存,就会触发缺页异常。操作系统会检查这次访问是否合法;如果合法但页不在内存,就需要把它从磁盘或其他后备存储加载进来。
它很慢,是因为:
- 需要陷入内核;
- 可能触发磁盘 IO;
- 可能还要挑选牺牲页并写回。
内存访问通常是纳秒级,而磁盘或 SSD 访问通常是微秒到毫秒级,所以严重缺页能把性能直接拉崩。
#148. 什么是 TLB?为什么它对性能很重要?
#知识点
- 地址翻译缓存
- 缓存页表映射
- TLB miss 会增加地址翻译成本
- 多级页表下更关键
#详细解答
TLB 是地址翻译缓存,用来缓存最近访问过的虚拟页到物理页框映射。因为每次内存访问前都要先做地址翻译,如果每次都查多级页表,开销会非常大。
如果 TLB hit,地址翻译很快;如果 TLB miss,就得走更慢的页表遍历流程。因此程序的局部性越好,TLB 命中率通常越高,性能越稳定。
所以 TLB 的本质和 CPU cache 很像,都是在用局部性换速度。
#149. 堆和栈有什么区别?
#知识点
- 自动分配 vs 动态分配
- 生命周期不同
- 管理方式不同
- 栈快但空间有限,堆灵活但管理复杂
#详细解答
栈通常由编译器和运行时自动管理,主要存函数调用帧、局部变量和返回地址;堆则用于动态分配对象,由程序或运行时显式申请和释放。
主要区别是:
- 生命周期:栈变量通常随作用域结束自动释放;堆对象更灵活。
- 速度:栈分配通常更快;堆分配要经过分配器。
- 空间:栈空间较小,适合短生命周期小对象;堆更适合大对象和动态生命周期对象。
所以性能敏感代码里,能用栈解决时通常比无脑堆分配更好。
#150. 什么是 mmap?它和 read/write 有什么区别?
#知识点
- 文件映射到虚拟地址空间
- 惰性加载
- 零拷贝/少拷贝思路
- 顺序读写 vs 映射访问
#详细解答
mmap 是把文件或设备的一部分映射到进程虚拟地址空间,之后程序可以像访问内存一样访问文件内容。
它和 read/write 的区别主要在于:
read/write更像把数据主动搬进用户缓冲区;mmap更像把文件页纳入虚拟内存体系,按需加载。
mmap 在大文件处理、共享内存和零拷贝优化中很常见,但它不是总更快,访问模式、缺页行为和映射管理成本都要一起考虑。