OS · 系统底层 / 面试高频
操作系统速查
进程线程、虚拟内存、IO 模型、零拷贝、死锁、调度算法、文件系统、信号控制与 IPC——操作系统面试最常追问的 57 个核心考点一张表收齐,随查随用。
57条速查
8大主题
∞持续更新
📖 速查表
点击展开各小节
🧵 进程与线程
| 名称 | 说明 | 要点 / 示例 |
|---|---|---|
| 进程 vs 线程 | 进程是资源分配的最小单位(独立地址空间),线程是 CPU 调度的最小单位(共享进程的堆与方法区,私有栈与寄存器) | 进程隔离性强、切换开销大;线程通信廉价但需同步 一个进程崩溃通常不影响其他进程 面试高频 |
| 进程五态转换 | 创建 → 就绪 → 运行 → 阻塞 → 终止;运行态时间片耗尽回就绪,等待事件进入阻塞,事件完成回到就绪 | 关键转换:运行 → 阻塞是主动行为(等待 IO) 阻塞 → 就绪是被动行为(IO 完成)阻塞不能直接到运行 |
| 线程创建方式 | 继承 Thread、实现 Runnable/Callable、线程池 ThreadPoolExecutor、CompletableFuture | 生产环境一律用线程池,避免频繁创建销毁 new Thread() 裸创建被阿里规约禁止 |
| 协程 | 用户态轻量级「线程」,由程序自身调度而非内核,切换不陷入内核态,成本极低 | 单线程可跑数十万协程;Go 的 goroutine、Kotlin 协程、Java 虚拟线程 单线程内避免阻塞调用 |
| 上下文切换成本 | 保存当前寄存器/程序计数器/内核栈,恢复下一个任务状态;进程切换还需切换页表使缓存失效 | 线程切换约几微秒,进程切换更贵(TLB 刷新) 过高切换的排查:vmstat 看 cs 列 面试高频 |
| 进程间通信 IPC | 管道(匿名/命名)、消息队列、共享内存、信号量、信号、Socket | 共享内存最快(零拷贝、需配信号量同步) Socket 是唯一可跨主机的 IPC 方式 必背 |
| 线程同步方式 | 互斥锁(独占)、读写锁(读共享写独占)、条件变量(等待/唤醒)、信号量(计数控制)、CAS 无锁 | Java 对应 synchronized/ReentrantLock/ReentrantReadWriteLock/Semaphore/Atomic* |
🧠 内存管理
| 名称 | 说明 | 要点 / 示例 |
|---|---|---|
| 虚拟内存 | 为每个进程提供独立的抽象地址空间,通过页表映射到物理内存,配合换页可运行大于物理内存的程序 | 优点:隔离、扩容、按需加载(局部性原理) free -h 中 buff/cache 即换页缓存 必背 |
| 分页 | 把内存切成固定大小的页(常见 4KB),按页映射与分配,消除外部碎片,内部碎片最多一页 | 物理内存按页帧管理;地址 = 页号 × 页大小 + 页内偏移 |
| 分段 | 按逻辑单元(代码段/数据段/栈段)划分,段长可变,便于共享与保护,但会产生外部碎片 | 现代系统主流方案:段页式——先分段、段内再分页 |
| 页表与 TLB | 页表记录虚拟页 → 物理页帧的映射;TLB 是页表的高速缓存(MMU 内),命中则免查内存页表 | 多级页表节省空间但增加查询次数,TLB 命中率是关键 面试高频 |
| 缺页中断 | 访问的页不在物理内存时触发缺页异常,内核从磁盘调入该页;若内存已满先按置换算法淘汰一页 | 频发缺页 = 颠簸/抖动,CPU 大量耗在换页上 排查:sar -B 观察 majflt 指标 |
| FIFO / OPT 置换 | FIFO 淘汰最早进入的页(可能出现 Belady 异常:页框越多缺页反而越多);OPT 淘汰未来最久不用的页 | OPT 是理论最优、不可实现,作为评估基准 FIFO 3 页框 10 缺页 → 4 页框 12 缺页即 Belady 异常 易混淆 |
| LRU / Clock 置换 | LRU 淘汰最久未使用的页(硬件开销大);Clock 用引用位近似 LRU:指针扫描,1 清 0 跳过,遇 0 淘汰 | 工程实现常用 Clock(二次机会法) Redis 的近似 LRU 用采样实现,思路同源 面试常考 |
📡 IO 模型与零拷贝
这节的关键是把「阻塞 / 非阻塞」与「同步 / 异步」两组概念分开记:前者看线程等不等,后者看拷贝由谁做;零拷贝解决的是内核态与用户态之间的多余拷贝。
| 名称 | 说明 | 要点 / 示例 |
|---|---|---|
| BIO 阻塞 IO | 读写全程阻塞,一个连接独占一个线程处理,连接数大时线程开销爆炸 | ServerSocket.accept() / read() 均阻塞 适合连接少且固定的场景 并发瓶颈 |
| NIO 同步非阻塞 | 无数据立即返回而不阻塞,配合多路复用器一个线程管理大量连接(Reactor 模式) | Java 的 Channel + Selector + ByteBuffer Netty 的底层基础 必背 |
| AIO 异步 IO | 发起读后立即返回,内核完成拷贝后回调通知(Proactor 模式),全程无阻塞 | Linux 底层支持有限,实际高并发多为 NIO + epoll Netty 曾移除 AIO 支持 |
| select / poll | 把 fd 集合从用户态拷到内核态轮询检查;select 上限 1024 且每次需重置集合,poll 无上限但仍是 O(n) 轮询 | 共同缺陷:fd 拷贝开销 + O(n) 遍历 + 就绪后仍需用户态逐个检查 易混淆 |
| epoll | 事件驱动:epoll_create/ctl/wait 三板斧,红黑树管理 fd、就绪链表返回结果,只返回就绪的 fd | O(1) 就绪通知,支持百万级连接,触发模式 LT/ET Redis、Nginx、Netty(epoll transport)的基石 面试高频 |
| 零拷贝 sendfile | 传统读写:磁盘 → 内核缓冲 → 用户态 → Socket 缓冲 → 网卡,4 次拷贝 4 次上下文切换;sendfile 直接在内核态完成文件到 Socket 的传输 | Kafka、Nginx sendfile on; 使用 配合网卡 SG-DMA 可做到 2 次拷贝 0 次用户态切换 必背 |
| 零拷贝 mmap | 把文件映射到用户态虚拟内存,绕过 read 的内核→用户拷贝,写回时由内核刷盘;适合需修改数据的场景 | RocketMQ CommitLog、Kafka 索引文件采用 大量小文件映射反而更费 TLB 注意适用场景 |
| 缓冲 IO vs 直接 IO | 缓冲 IO 经过 PageCache(读写合并、预读);直接 IO(O_DIRECT)绕过 PageCache 直达磁盘 | 数据库(MySQL InnoDB)用直接 IO 自管缓存,避免双重缓存 普通应用默认缓冲 IO 顺序写性能更佳 |
🔒 死锁
| 名称 | 说明 | 要点 / 示例 |
|---|---|---|
| 四个必要条件 | 互斥、占有且等待、不可剥夺、循环等待——四者同时成立才会死锁,破坏任意一个即可预防 | 必背 最常用突破口:破坏循环等待 → 全局统一加锁顺序 |
| 死锁预防 | 静态策略:一次性申请全部资源(破坏占有且等待)、可剥夺资源、资源有序分配(破坏循环等待) | 代价是资源利用率低;转账场景按账户 ID 排序加锁即典型应用 |
| 死锁避免 | 动态策略:银行家算法在分配前计算「安全序列」,不安全则不分配 | 需要预知最大资源需求,实际实现成本高,重在面试讲解 面试高频 |
| 死锁检测与恢复 | 构建资源分配图检测环路,发现后剥夺资源或回滚/杀死进程解除死锁 | 数据库死锁即此路线:InnoDB 检测回滚代价小的事务,抛 Deadlock found |
| 鸵鸟策略 | 假设死锁概率极低而不作处理,出问题再重启修复 | 多数通用操作系统的实际选择,权衡成本后的务实方案 |
| 排查手段 | Java 用 jstack pid(直接提示 Found one Java-level deadlock);系统级用 pstack pid 看线程栈 | 配合 top -Hp pid 定位线程,arthas thread -b 一键找阻塞源头 实战技能 |
⏱️ 调度算法
| 名称 | 说明 | 要点 / 示例 |
|---|---|---|
| FCFS 先来先服务 | 按到达顺序调度,公平且实现简单,但长作业会阻塞短作业(护航效应) | 对短作业不友好,平均周转时间长 |
| SJF / SRTF | 短作业优先(非抢占)/ 最短剩余时间优先(抢占),平均等待时间最优,但长作业可能饥饿 | 运行时间不可预知,实际用历史执行时长估算 饥饿风险 |
| RR 时间片轮转 | 就绪队列 FIFO,每个任务运行一个时间片后轮转,响应快且公平 | 时间片过大退化为 FCFS,过小则切换开销占比过高(常 20~100ms) |
| 优先级调度 | 按优先级选取任务,可抢占或非抢占;静态优先级会有低优先级饥饿问题 | 解法:老化机制(等待越久优先级渐增)避免饥饿 |
| 多级反馈队列 | 多个优先级队列,时间片逐级加倍;新任务进最高队列,用完时间片降级,兼顾响应时间与吞吐 | Unix/Linux 调度器的思想源头,面试高频 综合题常客 |
| 磁盘调度 FIFO | 按请求到达顺序寻道,公平但平均寻道距离长 | 适合 IO 负载轻的场景 |
| SSTF 最短寻道 | 每次选距当前磁头最近的请求,平均寻道短,但边缘请求可能饥饿 | 贪心思想,只顾局部最优 |
| SCAN 与 C-SCAN | SCAN(电梯算法)磁头沿一个方向服务到尽头再折返;C-SCAN 单向服务、到头直接回到起点重新扫描,等待时间更均匀 | C-LOOK 是 C-SCAN 的优化:只回到最早请求处而非磁盘物理端点 易混淆 |
📁 文件系统与内核
| 名称 | 说明 | 要点 / 示例 |
|---|---|---|
| inode | 索引节点,存储文件元数据(权限、大小、时间戳、数据块指针),不存文件名;文件名只是目录项中对 inode 的引用 | ls -i 查看;inode 耗尽即使磁盘有空间也无法新建文件 易混淆 |
| 软链接 vs 硬链接 | 硬链接:目录项直接指向同一 inode(ln),删除原文件不影响;软链接:独立 inode 存路径(ln -s),原文件删除则失效 | 硬链接不能跨文件系统、不能对目录创建;软链接均可 面试高频 |
| VFS | 虚拟文件系统:内核抽象层,统一 open/read/write 接口屏蔽 ext4/xfs/NFS 等差异 | 「一切皆文件」的实现基础:普通文件、设备、Socket、管道都是 VFS 语义 必背 |
| 用户态 / 内核态 | CPU 特权级分级(Ring3/Ring0),内核态可执行特权指令与访问全部内存;切换靠中断/系统调用/异常触发 | 切换需保存用户态上下文 + 换内核栈,开销微秒级 strace -c 统计系统调用耗时 面试高频 |
| 系统调用 | 用户程序请求内核服务的唯一合法入口,触发软中断/陷入指令后由内核代为执行并返回结果 | 一次 read() = 系统调用陷入 + 拷贝;减少调用次数(缓冲/批量)是性能优化常见手段 |
| 中断 | 外中断(硬件:时钟、磁盘完成)异步打断 CPU;内中断(异常:缺页、除零)同步产生;上半部快速响应、下半部(软中断/tasklet)延迟处理 | cat /proc/interrupts 查看;si 过高说明软中断是瓶颈 实战技能 |
| 文件描述符 fd | 进程打开文件/Socket/管道后得到的非负整数索引,指向内核打开文件表项;0/1/2 固定为标准输入/输出/错误 | 上限 ulimit -n(默认 1024),高并发服务需调大 排查 Too many open files |
🧾 信号与进程控制
进程「怎么停、怎么挪后台」是运维与排障的日常:先给优雅退出的机会,再考虑强杀;后台常驻交给 nohup 或系统服务托管。
| 操作 | 说明 | 要点 / 示例 |
|---|---|---|
| kill -15 pid | 发送 SIGTERM,请求进程优雅退出 | 可被捕获:应用有机会摘流量、刷缓冲、释放锁再退出;kill 命令缺省即此信号 停进程首选 |
| kill -9 pid | 发送 SIGKILL,强制终止,不可捕获、不可忽略 | 进程毫无清理机会,可能留下半写数据、锁文件与未清理的临时目录 先 -15 等待无果再 -9,别一上来就强杀 最后手段 |
| kill -HUP pid | 发送 SIGHUP,传统上表示「重读配置」 | nginx -s reload 底层就是向 master 发 HUP;sshd 修改配置后同样用 HUP 重载 |
| Ctrl+Z | 向前台任务发 SIGTSTP,暂停并移入后台作业队列 | 进程停在 STOP 态:不占 CPU 但仍占内存;执行中的 vim / 耗时命令可借此临时让出终端 |
| jobs / fg / bg | 作业控制三件套:查看、调回前台、转后台继续 | jobs -l 列出作业号与 PID;fg %1 调回前台;bg %1 让暂停的作业在后台继续跑 配套使用 |
| nohup cmd ... | 让进程忽略 SIGHUP,登出或断开终端后继续运行 | nohup java -jar app.jar > app.log 2>&1 &:忽略 HUP + 后台 + 日志重定向一步到位 常驻标配 |
| cmd & | 仅放入后台执行,不提供任何挂断保护 | 终端退出时 shell 会向后台作业发 SIGHUP,进程常随终端一起死 临时任务可用,长驻任务务必搭配 nohup 或进程守护 易踩坑 |
| disown %1 | 把作业从 shell 作业表移除,终端退出后不再向它发 SIGHUP | 补救「忘了加 nohup」的常用手段;生产环境的守护交给 systemd / supervisor 更稳 实战技能 |
🚥 进程间通信 IPC 对比
同一台机器上的进程怎么传数据?速度、消息边界、同步能力各有取舍——选型口诀:高频大数据共享内存,一般解耦消息队列,跨机器只能 socket。
| 方式 | 速度与特点 | 适用场景 / 示例 |
|---|---|---|
| 匿名管道 | | 内核缓冲的字节流,半双工、单向,仅限有亲缘关系的进程(父子)使用 | shell 管道的底层实现:cat app.log | grep ERROR | wc -l;随用随建、简单直接 最常见 |
| 命名管道 FIFO | 文件系统中有名字的管道(mkfifo),任意进程可打开,仍是半双工字节流 | mkfifo /tmp/p 后一端写一端读;无血缘关系进程间的轻量数据通道 |
| 消息队列 | 内核维护的消息链表:自带消息边界与类型,可按类型挑选读取,速度中等 | 要求「一条消息一个边界、可选择性消费」的场景;System V / POSIX 消息队列,思想与专业 MQ 同源 带边界 |
| 共享内存 + 信号量 | 同一块物理内存映射进多个进程地址空间,读写零次内核拷贝,速度最快 | 不带同步,必须配信号量/互斥锁防竞态;多进程高频交换大块数据(数据库共享缓冲、多进程推理)面试高频 |
| Socket | 唯一可跨主机;本机 Unix 域 Socket 不走协议栈,比 127.0.0.1 的 TCP 更快且不占端口 | Docker daemon(/var/run/docker.sock)、MySQL 本机连接常用 Unix 域 socket;跨机器通信的事实标准 |
| 信号 signal | 异步事件通知而非数据通道,只有「编号 + 到达」这一比特语义 | kill -15 / -9 / -HUP 本质都是发信号;适合事件通知与简单控制,无法承载业务数据 |