Skip to content

操作系统高频考点

进程和线程相关


用户态和内核态


内核负责管理和控制硬件资源,为了避免应用程序直接访问硬件资源可能导致的问题,操作系统将应用程序和内核隔离,确保内核独立控制硬件资源。

因此,操作系统内核运行在两种模式下:

  • 内核态:操作系统具有最高权限,可以访问所有资源并执行所有指令。
  • 用户态:应用程序只能访问授权资源,执行受限指令集,需要通过系统调用来请求操作系统服务。

当应用程序需要进行系统调用(如读写文件)时,会触发用户态向内核态的切换。CPU 会暂停当前进程,保存状态,切换到内核态执行操作,完成后再切换回用户态,恢复进程执行,因此涉及内核态和用户态的切换操作会造成一定的性能开销。


进程,线程和协程


  1. 进程:

    • 进程是系统资源分配的基本单位
    • 进程拥有独立的执行环境和私有的基本运行资源集合,包括自己的内存空间。
    • 一个应用程序可能由多个协作的进程组成。
  2. 线程:

    • 线程是系统调度的基本单位
    • 线程共享进程的资源,包括内存和打开的文件,减少了系统调用和时间消耗。
    • 线程比进程更轻量,包含程序、数据和线程控制块(TCB)。
  3. 协程:

    • 协程(Coroutine),也称纤程,是用户态的概念,不被操作系统感知。
    • 协程允许用户控制执行逻辑流,避免了操作系统级的线程阻塞和资源竞争。
    • 协程通过异步方式避免了回调地狱(callback hell),提高了代码的可读性。

引入线程和协程的必要性:

  • 线程的引入是为了减少进程间切换的上下文切换成本,允许在一个进程内并发执行多个子任务。
  • 协程的引入是为了进一步优化资源利用,允许用户控制任务切换,避免了多线程中的CPU资源竞争和不必要的资源浪费。

进程的状态


操作系统的进程有三种状态:

  • 运行(running):进程已获得CPU,处于运行中的状态。在单处理机系统中,只有一个进程处于执行状态,在多处理机系统中,则有多个进程处于执行状态。
  • 就绪(ready):进程具备运行条件,只要再获得CPU,便可立即执行,进程这时的状态称为就绪状态。在一个系统中处于就绪状态的进程可能有多个。
  • 等待(wait):又称阻塞态或睡眠态,一个进程因(请求I/O、等待I/O完成等)事件而暂停运行,这时即使把处理机分配给进程也无法运行,故称该进程处于阻塞状态。

进程调度算法


算法核心思想优点缺点适用场景
时间片轮转固定时间片轮流执行公平、响应快周转时间长、切换开销大分时系统
优先级调度按优先级高低执行区分任务重要性可能饥饿、需维护优先级实时系统
多级反馈队列动态调整队列优先级和时间片灵活适应不同任务类型配置复杂、参数敏感通用操作系统

时间片轮转调度算法(Round Robin, RR)

  • 实现原理:每个进程被分配一个固定时间片(Time Quantum),按就绪队列顺序依次执行。若进程在时间片内未完成,则被抢占并重新加入队列尾部,等待下一次调度。
  • 特点:
    • 抢占式:时间片结束时强制切换进程。
    • 公平性:所有进程获得均等的CPU时间。

优先级调度算法(Priority Scheduling)

  • 实现原理:为每个进程分配优先级,调度时选择优先级最高的进程执行。可分为静态优先级(固定)或动态优先级(根据等待时间、执行历史等调整)。
  • 特点:
    • 抢占式/非抢占式:抢占式允许高优先级进程立即抢占CPU。
    • 饥饿问题:低优先级进程可能长期等待,需通过“老化”(逐渐提升优先级)解决。

多级反馈队列调度算法(Multilevel Feedback Queue, MLFQ)

  • 实现原理: 设置多个优先级队列,新进程进入最高优先级队列。每个队列的时间片大小递增(如第一级队列时间片短,后续队列时间片加长)。进程未完成则降级到下一队列;若完成或主动释放CPU(如I/O操作),可能重新进入较高队列。
  • 特点
    • 动态调整:根据进程行为(CPU密集型或I/O密集型)反馈调整优先级。
    • 兼顾长短作业:短作业快速响应,长作业减少切换开销。

I/O 相关


操作系统I/O模型


模型阻塞阶段用户态参与复杂度性能
同步阻塞I/O全程阻塞被动等待低(高并发差)
同步非阻塞I/O仅拷贝阶段阻塞主动轮询中(CPU占用高)
I/O复用阻塞在复用函数被动监听+主动处理高(epoll优化)
信号驱动I/O仅拷贝阶段阻塞异步信号通知中(适用场景少)
异步I/O全程无阻塞完全异步回调最高(依赖系统支持)

同步阻塞型I/O模型(Blocking I/O)

  • 实现原理:进程在 recv 系统调用期间阻塞,直到数据从内核复制到用户空间。
  • 特点:
    -简单易用:代码逻辑直观。
    -资源浪费:进程在等待期间无法执行其他任务,高并发时需多线程/进程,开销大。

同步非阻塞型I/O模型(Non-blocking I/O)

  • 实现原理:进程调用 recv 时,若内核数据未就绪,立即返回错误,进程需轮询重试直到数据就绪,随后阻塞完成数据拷贝。
  • 特点:
    • 部分非阻塞:仅等待数据阶段非阻塞,拷贝阶段仍阻塞。
    • CPU 空转:频繁轮询消耗大量CPU资源。

I/O 复用模型(I/O Multiplexing)

  • 实现原理:通过 select、poll、epoll 系统调用,单线程监听多个文件描述符(fd)。进程阻塞在复用函数上,当任一 fd 数据就绪时,再调用 recv 进行数据拷贝。
  • 特点:
    • 高效管理多连接:单线程处理多 I/O,减少线程/进程数。
    • 两次系统调用:先 select 检测就绪状态,再 recv` 贝数据。

信号驱动I/O模型(Signal-driven I/O)

  • 实现原理:通过sigaction注册信号函数,在内核数据准备好时中断当前程序执行信号函数。
  • 特点:
    • 异步通知:避免轮询,减少CPU消耗。
    • 局限性:仅适用于UDP等支持信号驱动的协议,且信号处理需考虑可重入性。

异步 I/O 模型(Asynchronous I/O, AIO)

  • 实现原理:通过aio_read系统调用,内核在数据准备好并复制到用户进程空间后执行指定函数,进程在此过程中可以执行其他任务。
  • 特点:
    • 真正异步:进程全程无阻塞,完全由内核完成I/O操作。
    • 复杂性高:需系统支持(如Linux的 io_uring 、Windows的 IOCP)。

select、poll 和 epoll


技术fd长度限制遍历所有fd把fd从用户态copy到内核态
select1024
poll无限制
epoll无限制

select

  • 最早的I/O多路复用技术,可以监听read、write、except的文件描述符(fd)。
  • 缺点:单个进程最多只能监听1024个文件描述符,且需要将包含大量fd的数组整体复制于用户态和内核态之间,导致开销随文件描述符数量增加而线性增大。

poll

  • 基于select,支持监听更多的文件描述符,但没有最大限制。
  • 同样需要轮询pollfd来获取就绪的fd,所有fds在内核态和用户态中来回切换,影响效率。

epoll

  • 基于Linux 2.4.5,优化了复杂度,支持更多的文件描述符,效率更高。
  • 通过epoll_ctl注册事件时,将所有fd拷贝进内核,而不是在epoll_wait时重复拷贝。
  • epoll_wait直接使用就绪的fd(O(1)),不需要像select和poll那样手动遍历(O(n))。
  • 支持的fd上限是系统最大可打开文件的数目,通常远大于2048,与系统内存大小有关。

epoll的两种模式

  • LT(level trigger)模式:默认模式,事件通知后,应用程序可以不立即处理,下次调用epoll_wait时会再次通知。
  • ET(edge trigger)模式:事件通知后,应用程序必须立即处理,否则下次调用epoll_wait时不会再次通知。 ET模式减少了事件被重复触发的次数,效率更高,但需要使用非阻塞socket以避免处理多个文件描述符时的阻塞问题。

内存相关


分段分页


方法划分单位碎片问题地址转换硬件需求优势
分段逻辑段外部碎片(需紧凑整理)段表(基址+界限)段寄存器+界限检查逻辑隔离与保护
分页固定大小的页仅内部碎片(最后一页浪费)页表(虚拟页→物理页帧)MMU+TLB加速高效内存管理、虚拟内存

分段(Segmentation)

  • 逻辑划分:将程序的内存空间按逻辑模块划分为多个段(如代码段、数据段、堆栈段等),每个段对应程序的一个功能部分。
  • 动态大小:段的大小不固定,由实际需求决定。
  • 段表管理:通过段表(Segment Table)记录每个段的基址(起始地址)和界限(长度),实现逻辑地址到物理地址的转换。

在分段的映射方法中,每次换入换出内存的都是整个程序,这样会造成大量的磁盘访问操作,且每个段大小不一,频繁分配/释放后易产生内存碎片,需通过紧凑(Compaction)整理,但开销较大,导致效率低下。

分页(Paging)

  • 物理划分:将物理内存和虚拟地址空间划分为固定大小的页(如4KB),消除外部碎片。
  • 页表映射:通过页表(Page Table)建立虚拟页到物理页帧的映射,支持非连续分配。
  • 硬件支持:由MMU(内存管理单元)加速地址转换,如TLB(快表)缓存常用页表项。

分页方法允许进程使用超过物理内存的地址空间,通过页面置换(如LRU算法)将不活跃页换出到磁盘,固定页大小减少外部碎片,仅存在内部碎片(最后一页未用满)。

现代操作系统的内存管理

  • 段页式结合:如x86架构,先分段再分页,兼顾逻辑保护与物理效率(但x86-64弱化分段,主要用分页)。
  • 分页主导:Linux/Windows等系统以分页为核心,分段仅用于兼容性或特定场景(如权限控制)。
  • 虚拟内存扩展:分页支持按需调页、写时复制(Copy-on-Write)等高级特性,优化多任务性能。

零拷贝


传统的数据传输,数据需要多次在内核态和用户态之间复制,导致性能损耗,零拷贝技术可以减少或消除数据在内存中的冗余拷贝次数,从而降低 CPU 和内存的开销,提升系统性能。

以下是传统拷贝与零拷贝技术的对比表格,从 拷贝次数、上下文切换、CPU 参与度 等关键维度进行对比:

技术数据拷贝上下文切换CPU 参与拷贝用户态参与支持系统
传统拷贝2 次 DMA + 2 次 CPU 拷贝4 次2 次所有系统
mmap + write2 次 DMA + 1 次 CPU 拷贝3 次1 次是(需调用)Linux/Unix
sendfile2 次 DMA + 1 次 CPU 拷贝2 次1 次Linux 2.4+
sendfile + SG-DMA2 次 DMA(零 CPU 拷贝)2 次0 次Linux 2.4+(需硬件支持)

mmap + write

  • 实现原理:使用内存映射(mmap)将内核缓冲区的数据映射到用户空间,避免显式拷贝。
  • 过程:
    • 磁盘 → 内核缓冲区(DMA 拷贝)。
    • 内核缓冲区与用户空间通过 mmap 共享内存(无需 CPU 拷贝)。
    • 用户程序调用 write,数据从内核缓冲区 → Socket 缓冲区(CPU 拷贝)。
    • Socket 缓冲区 → 网卡(DMA 拷贝)
  • 优化效果:四次用户态/内核态的切换,三次数据拷贝,减少了 1 次 CPU 拷贝。

sendfile 系统调用

  • 实现原理:通过 sendfile 系统调用直接将数据从文件描述符传输到 Socket,全程在内核态完成。
  • 过程:
    • 磁盘 → 内核缓冲区(DMA 拷贝)。
    • 内核缓冲区 → Socket 缓冲区(CPU 拷贝)。
    • Socket 缓冲区 → 网卡(DMA 拷贝)。
  • 优化效果:完全消除用户态参与,三次数据拷贝,仅 1 次 CPU 拷贝。

sendfile + SG-DMA(Scatter-Gather DMA)

  • 实现原理:结合 sendfile 和 Scatter-Gather DMA,消除最后的 CPU 拷贝。
  • 过程:
    • 磁盘 → 内核缓冲区(DMA 拷贝)。
    • 内核缓冲区 → 网卡(SG-DMA 直接传输,无需 CPU 拷贝)。
  • 优化效果:两次数据拷贝,零 CPU 拷贝,实现真正的“零拷贝”。

页面历史

Released under the CC BY-NC-SA 4.0 License

Copyright © 2025 OFFER DASH