OS · 系统底层 / 面试高频

操作系统速查

进程线程、虚拟内存、IO 模型、零拷贝、死锁、调度算法、文件系统、信号控制与 IPC——操作系统面试最常追问的 57 个核心考点一张表收齐,随查随用。

57条速查 8大主题 持续更新

📖 速查表

点击展开各小节

🧵 进程与线程
名称说明要点 / 示例
进程 vs 线程 进程是资源分配的最小单位(独立地址空间),线程是 CPU 调度的最小单位(共享进程的堆与方法区,私有栈与寄存器) 进程隔离性强、切换开销大;线程通信廉价但需同步
一个进程崩溃通常不影响其他进程 面试高频
进程五态转换 创建 → 就绪 → 运行 → 阻塞 → 终止;运行态时间片耗尽回就绪,等待事件进入阻塞,事件完成回到就绪 关键转换:运行 → 阻塞是主动行为(等待 IO)
阻塞 → 就绪是被动行为(IO 完成)阻塞不能直接到运行
线程创建方式 继承 Thread、实现 Runnable/Callable、线程池 ThreadPoolExecutorCompletableFuture 生产环境一律用线程池,避免频繁创建销毁
new Thread() 裸创建被阿里规约禁止
协程 用户态轻量级「线程」,由程序自身调度而非内核,切换不陷入内核态,成本极低 单线程可跑数十万协程;Go 的 goroutine、Kotlin 协程、Java 虚拟线程 单线程内避免阻塞调用
上下文切换成本 保存当前寄存器/程序计数器/内核栈,恢复下一个任务状态;进程切换还需切换页表使缓存失效 线程切换约几微秒,进程切换更贵(TLB 刷新)
过高切换的排查:vmstatcs面试高频
进程间通信 IPC 管道(匿名/命名)、消息队列、共享内存、信号量、信号、Socket 共享内存最快(零拷贝、需配信号量同步)
Socket 是唯一可跨主机的 IPC 方式 必背
线程同步方式 互斥锁(独占)、读写锁(读共享写独占)、条件变量(等待/唤醒)、信号量(计数控制)、CAS 无锁 Java 对应 synchronized/ReentrantLock/ReentrantReadWriteLock/Semaphore/Atomic*
进程五态转换
进程五态转换:就绪⇄运行靠调度切换,运行中等待 IO 会进入阻塞,IO 完成后回到就绪重新排队
🧠 内存管理
名称说明要点 / 示例
虚拟内存 为每个进程提供独立的抽象地址空间,通过页表映射到物理内存,配合换页可运行大于物理内存的程序 优点:隔离、扩容、按需加载(局部性原理)
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 本质都是发信号;适合事件通知与简单控制,无法承载业务数据