#一、操作系统高频笔试题

#141. 进程和线程的区别是什么?

#知识点

  • 资源分配单位 vs 调度执行单位
  • 地址空间是否共享
  • 切换成本
  • 崩溃隔离与通信成本

#详细解答

进程是操作系统进行资源分配的基本单位,通常拥有独立的虚拟地址空间、文件描述符表和系统资源;线程是 CPU 调度和执行的基本单位,同一进程内的多个线程共享地址空间和大部分资源,但各自有独立栈和寄存器上下文。

最关键的区别有四点:

  1. 资源边界:进程彼此隔离,线程共享进程资源。
  2. 切换成本:线程切换通常比进程切换轻,因为不需要完整切换地址空间。
  3. 通信方式:进程间通信依赖 IPC,线程间通信更直接,但同步更复杂。
  4. 稳定性:进程隔离更强,一个线程把共享内存写坏,整个进程都可能崩掉。

一句话总结:进程更强调隔离,线程更强调并发。

#142. 用户态和内核态有什么区别?为什么要区分这两种模式?

#知识点

  • CPU 特权级
  • 用户程序权限受限
  • 内核控制硬件和关键资源
  • 系统调用是主要入口

#详细解答

用户态和内核态的本质区别是权限不同。用户态程序不能直接执行特权指令,也不能直接访问硬件和关键内核数据结构;内核态拥有更高权限,可以调度 CPU、管理内存、控制设备和处理中断。

之所以要区分,是为了保证系统安全和稳定。如果普通应用都能直接改页表、关中断、写磁盘控制器,系统会立刻失去边界。

程序通常通过系统调用从用户态进入内核态,例如:

  • read/write
  • open
  • fork
  • mmap

所以用户态/内核态不是抽象概念,而是系统安全边界。

#143. 什么是上下文切换?为什么上下文切换过多会让系统变慢?

#知识点

  • 保存和恢复执行现场
  • 线程切换 vs 进程切换
  • cache / TLB 污染
  • 切换本身不做业务计算

#详细解答

上下文切换是 CPU 从一个线程或进程切到另一个执行体时,保存当前执行状态并恢复下一个执行状态的过程。这里的状态包括寄存器、程序计数器、栈指针,进程切换时还可能涉及地址空间相关状态。

它会让系统变慢,主要因为:

  1. 切换本身不产生业务价值;
  2. 会破坏 cache 局部性;
  3. 会降低 TLB 命中率;
  4. 线程过多时调度开销显著上升。

因此高并发系统的一个常见误区就是“线程越多越好”,实际上线程太多经常先把系统拖进上下文切换地狱。

#144. 什么是死锁?死锁产生的必要条件有哪些?

#知识点

  • 互斥
  • 占有并等待
  • 不可剥夺
  • 循环等待

#详细解答

死锁是多个执行体彼此等待对方持有的资源,最终谁也无法继续执行的状态。经典四个必要条件是:

  1. 互斥:资源一次只能给一个执行体用;
  2. 占有并等待:已经拿到一部分资源,还在等别的资源;
  3. 不可剥夺:资源不能被强行抢走;
  4. 循环等待:等待关系形成环。

面试里更高分的点在于:只要破坏其中任意一个条件,就能避免死锁。例如统一加锁顺序,本质上是在破坏循环等待。

#145. 什么是虚拟内存?它解决了什么问题?

#知识点

  • 虚拟地址与物理地址分离
  • 每个进程拥有独立地址空间
  • 按页映射
  • 提升隔离性与利用率

#详细解答

虚拟内存的核心思想是:程序访问的是虚拟地址,而不是直接访问物理内存。硬件和操作系统负责把虚拟地址翻译成物理地址。

它主要解决三件事:

  1. 隔离性:每个进程看到自己的独立地址空间;
  2. 抽象性:程序不用关心自己真实放在物理内存哪里;
  3. 利用率:可以按需加载和换页,把不活跃页放到后备存储。

所以虚拟内存不是“凭空造更多内存”,而是让内存管理更灵活、更安全。

#146. 什么是分页?页表是做什么的?

#知识点

  • 虚拟地址空间切成页
  • 物理内存切成页框
  • 页表记录映射关系
  • 页表项包含权限、存在位、脏位等

#详细解答

分页是虚拟内存的常见实现方式。它把虚拟地址空间切成固定大小的页,把物理内存切成同样大小的页框,再通过页表记录二者映射关系。

页表项通常不只记录地址,还包含:

  • 页面是否在内存中;
  • 是否可写;
  • 是否被访问过;
  • 是否被修改过。

面试里要注意强调:分页带来了灵活性,但页表本身也有成本,所以才需要多级页表和 TLB

#147. 什么是缺页异常(page fault)?为什么缺页会很慢?

#知识点

  • 访问的页当前不在物理内存
  • 陷入内核
  • 可能需要磁盘换入
  • IO 远慢于内存访问

#详细解答

当程序访问某个虚拟页时,如果这个页当前没有映射到物理内存,就会触发缺页异常。操作系统会检查这次访问是否合法;如果合法但页不在内存,就需要把它从磁盘或其他后备存储加载进来。

它很慢,是因为:

  1. 需要陷入内核;
  2. 可能触发磁盘 IO;
  3. 可能还要挑选牺牲页并写回。

内存访问通常是纳秒级,而磁盘或 SSD 访问通常是微秒到毫秒级,所以严重缺页能把性能直接拉崩。

#148. 什么是 TLB?为什么它对性能很重要?

#知识点

  • 地址翻译缓存
  • 缓存页表映射
  • TLB miss 会增加地址翻译成本
  • 多级页表下更关键

#详细解答

TLB 是地址翻译缓存,用来缓存最近访问过的虚拟页到物理页框映射。因为每次内存访问前都要先做地址翻译,如果每次都查多级页表,开销会非常大。

如果 TLB hit,地址翻译很快;如果 TLB miss,就得走更慢的页表遍历流程。因此程序的局部性越好,TLB 命中率通常越高,性能越稳定。

所以 TLB 的本质和 CPU cache 很像,都是在用局部性换速度。

#149. 堆和栈有什么区别?

#知识点

  • 自动分配 vs 动态分配
  • 生命周期不同
  • 管理方式不同
  • 栈快但空间有限,堆灵活但管理复杂

#详细解答

栈通常由编译器和运行时自动管理,主要存函数调用帧、局部变量和返回地址;堆则用于动态分配对象,由程序或运行时显式申请和释放。

主要区别是:

  1. 生命周期:栈变量通常随作用域结束自动释放;堆对象更灵活。
  2. 速度:栈分配通常更快;堆分配要经过分配器。
  3. 空间:栈空间较小,适合短生命周期小对象;堆更适合大对象和动态生命周期对象。

所以性能敏感代码里,能用栈解决时通常比无脑堆分配更好。

#150. 什么是 mmap?它和 read/write 有什么区别?

#知识点

  • 文件映射到虚拟地址空间
  • 惰性加载
  • 零拷贝/少拷贝思路
  • 顺序读写 vs 映射访问

#详细解答

mmap 是把文件或设备的一部分映射到进程虚拟地址空间,之后程序可以像访问内存一样访问文件内容。

它和 read/write 的区别主要在于:

  1. read/write 更像把数据主动搬进用户缓冲区;
  2. mmap 更像把文件页纳入虚拟内存体系,按需加载。

mmap 在大文件处理、共享内存和零拷贝优化中很常见,但它不是总更快,访问模式、缺页行为和映射管理成本都要一起考虑。