Skip to content

操作系统 速查卡

🎯 覆盖 16 题 | ⭐ 高频 10 题 | 预计扫描 9 分钟 📌 先看⭐一句话答案 → 展开要点 → 自测清单检验


一、进程与线程

知识地图:进程(资源分配) → 线程(调度单位) → 协程(用户态轻量) 调度:FCFS/SJF/RR → MLFQ(现代主流) | 通信:管道/共享内存/Socket | 死锁:四条件+四策略

⭐ 进程 vs 线程

一句话: 进程是 OS 资源分配的基本单位,线程是 CPU 调度和执行的基本单位;同进程的线程共享地址空间,跨进程完全隔离。

维度进程线程
地址空间独立虚拟地址空间,完全隔离共享进程地址空间(堆/全局/代码段)
独有资源内存、文件描述符、信号处理表仅有栈、寄存器、PC
创建开销大:分配地址空间+页表+拷贝资源小:复用进程资源,只分配线程栈
切换开销大:切换页表(CR3),TLB 全失效小:不切换地址空间,TLB 部分保留
通信IPC(管道/共享内存/Socket 等)直接读写共享变量(需同步)
健壮性一进程崩溃不影响其他一线程崩溃可能拖垮整个进程

Linux 内核中进程和线程底层都是 task_struct,线程 = 共享地址空间的进程(clone(CLONE_VM|...)

↳ 协程:用户态调度,无内核切换开销,一个线程内多协程串行;Go goroutine / Java 21 虚拟线程


⭐ 进程调度算法

一句话: MLFQ(多级反馈队列)是现代 OS 主流调度算法,兼顾响应时间和吞吐量——新进程进高优先级队列,时间片用完则降级,定期全提升防饥饿。

算法原理优点缺点
FCFS按到达顺序,非抢占简单公平护航效应:长作业堵后面
SJF最短作业优先平均等待最优无法预测时长;长作业饥饿
RR固定时间片轮转响应好、公平片太小→切换多;片太大→退化FCFS
优先级高优先级先执行重要任务优先低优先级饥饿(解决:aging)
MLFQ多级队列+反馈降级+定期Boost兼顾响应与吞吐实现复杂
MLFQ 示意:
Q1(最高,8ms) → 新进程从此开始; 用完降级
Q2(中,16ms)  → 用完继续降级
Q3(最低,32ms,RR) → 长进程在此轮转
定期 Priority Boost → 全部提升回 Q1(防饥饿)

⭐ 进程间通信(IPC)

一句话: 共享内存最快(不经内核中转),管道最简单(父子进程),Socket 跨机器;共享内存需配合信号量/互斥锁做同步。

IPC 方式方向速度适用场景关键特点
匿名管道单向父子进程半双工;ls | grep
有名管道 FIFO单向无亲缘进程文件形式,路径名定位
消息队列双向结构化异步内核链表,按类型读取
共享内存双向最快大量数据页表映射同一物理页;需同步
信号量--同步/互斥PV 原子操作;配合共享内存
信号单向通知(不传数据)kill -9 / Ctrl+C
Socket双向跨机器IP+Port;TCP/UDP/Unix Domain

管道/消息队列 = 2次拷贝(用户空间↔内核);共享内存 = 0次内核中转拷贝


⭐ 死锁

一句话: 死锁 = 多个进程互持对方所需资源,全部阻塞;四个必要条件缺一不可——互斥、持有等待、不可剥夺、循环等待。

四个必要条件:

条件说明
互斥资源同一时刻只能被一个进程占用
持有并等待持有资源同时请求其他被占资源
不可抢占资源不能被强制剥夺
循环等待P1→P2→...→Pn→P1 形成环

四种处理策略:

策略方法实用度
预防破坏条件:资源排序申请(破坏循环等待,最常用
避免银行家算法:分配前判安全序列低(开销大)
检测资源分配图找环
恢复终止进程 / 资源抢占 / 回退

↳ Java 排查:jstack 输出 "Found one Java-level deadlock" = 资源分配图环路检测


二、内存管理

知识地图:虚拟内存(隔离+扩展) → 分页(4KB消除外部碎片) → TLB(加速翻译) → 缺页中断(按需加载) → 页面置换(OPT/FIFO/LRU/Clock)

⭐ 虚拟内存

一句话: 每个进程有独立虚拟地址空间,MMU+页表将虚拟地址翻译为物理地址;按需加载(Demand Paging)+Swap 使可用内存大于物理内存。

四大好处:

  1. 进程隔离 — 互不访问对方物理内存
  2. 内存扩展 — 缺页中断 + Swap 实现按需加载
  3. 简化管理 — 统一虚拟地址布局(0~3G 用户/3G~4G 内核)
  4. 方便移植 — 程序只用虚拟地址,与物理无关
虚拟地址 = [VPN | Offset]
              ↓ 查页表(MMU)
物理地址 = [PFN | Offset]

基础:局部性原理(时间局部性=循环,空间局部性=数组遍历)


⭐ 分段 / 分页 / TLB

一句话: 分页(固定4KB)是现代主流,消除外部碎片但有少量内部碎片;TLB 是 MMU 内的页表高速缓存,命中率>99%,将地址翻译从 2 次内存访问降到 1 次。

维度分段分页段页式
划分逻辑结构(大小不等)固定 4KB先分段再分页
碎片外部碎片内部碎片少量内部碎片
地址段号+段内偏移页号+页内偏移段号+页号+偏移
现状已淘汰主流理论最优但复杂

TLB 流程: VPN→查TLB→Hit则直接得PFN→Miss则查页表→更新TLB→页不在内存则缺页中断

多级页表:树状结构按需创建,时间换空间,配合 TLB 损失极小


⭐ 页面置换算法

一句话: OPT 理论最优不可实现;LRU 性能接近 OPT 但开销大;Clock 是 LRU 的近似,实际 OS 广泛使用。

算法原理优缺点
OPT替换未来最久不用的页理论最优,无法实现(基准线)
FIFO替换最早进入的页简单;有 Belady 异常(帧增多缺页反增)
LRU替换最近最久未用的页接近 OPT;需硬件支持,开销大
Clock环形链表+引用位:0则换,1则清零跳过LRU 近似,实际 OS 主流

Belady 异常只有 FIFO 会出现;LRU/OPT 不会 Redis allkeys-lru = 近似 LRU(随机采样淘汰最久未用)


三、文件系统与 IO

知识地图:传统IO(4拷贝4切换) → mmap(3拷贝) → sendfile(3拷贝2切换,最优) → SG-DMA(2拷贝0CPU) IO多路复用:select(O(n),1024) → poll(O(n),无限) → epoll(O(1),红黑树+回调)

⭐ 零拷贝

一句话: sendfile 数据全程不经用户空间(1次syscall/2次切换),Kafka consumer 用 sendfile 从磁盘直接到网卡;mmap 用于索引文件随机读。

传统 read+write:  磁盘→DMA→内核缓存→CPU→用户buf→CPU→Socket buf→DMA→网卡  (4拷贝4切换)
mmap+write:      磁盘→DMA→内核缓存(mmap映射)→CPU→Socket buf→DMA→网卡       (3拷贝4切换)
sendfile:        磁盘→DMA→内核缓存→CPU→Socket buf→DMA→网卡                 (3拷贝2切换)
sendfile+SG-DMA: 磁盘→DMA→内核缓存→DMA→网卡                               (2拷贝2切换,0次CPU拷贝)
Kafka 操作技术作用
Consumer 读消息sendfile()磁盘→内核→网卡,不经 JVM
Broker 索引mmap()索引文件映射内存,随机读高效
Producer 写入顺序追加+Page Cache接近内存写入速度

⭐ epoll(vs select/poll)

一句话: epoll 用红黑树管理 fd + 就绪链表 + 回调机制,fd 注册一次即可,epoll_wait 只返回就绪 fd,O(1);select 每次拷贝全部 fd 并遍历,O(n)。

维度selectpollepoll
fd 上限1024无限无限
数据结构位图链表红黑树+就绪链表
fd 传递每次全量拷贝到内核同左注册一次(epoll_ctl)
检测方式遍历 O(n)O(n)回调加入就绪链表 O(1)
触发模式LTLTLT + ET
epoll_create → 创建红黑树+就绪链表
epoll_ctl    → fd 注册到红黑树,绑定回调
epoll_wait   → 直接返回就绪链表中的 fd

LT vs ET:

  • LT(默认):fd 有数据就一直通知,编程简单
  • ET(边缘):仅状态变化时通知一次,必须一次读完(配合非阻塞IO),高效

↳ Redis=单Reactor单线程+epoll;Netty=主从Reactor多线程+epoll;Nginx=多进程+epoll


四、Linux 实战

⭐ Linux CPU 飙高排查

一句话: top 找进程 → top -Hp 找线程 → printf '%x' 转十六进制 → jstack 搜线程栈 → 分析原因。

① top (Shift+P 按CPU排序) → 记录 PID
② top -Hp <PID>           → 找到高CPU线程 TID
③ printf '%x\n' <TID>     → 转十六进制(如12345→3039)
④ jstack <PID> | grep -A 30 'nid=0x3039'
⑤ 分析线程栈定位问题
常见原因线程栈特征排查
死循环/忙等待始终停留在业务方法检查 while(true)
频繁 GC"GC task thread"jstat -gcutil
锁竞争大量 BLOCKED检查锁粒度
正则回溯java.util.regex嵌套量词

非 Java:perf top -p &lt;PID&gt; / strace -cp &lt;PID&gt; / vmstat 1 10


补充速览

关键词核心答案
用户态/内核态用户态权限受限(Ring3),内核态可执行所有指令(Ring0);切换方式:系统调用/硬件中断/异常
系统调用用户程序请求内核服务的接口;syscall 指令触发特权级切换,开销远大于普通函数调用
进程状态New→Ready→Running→Blocked→Terminated;Blocked 不能直接到 Running,必须先回 Ready
缺页中断访问的页不在物理内存→MMU触发PageFault→OS从磁盘调入→更新页表+TLB;Major(磁盘IO,ms级)/Minor(已在内存,us级)
硬链接 vs 软链接硬链接=同inode多目录项(不能跨FS/不能链目录);软链接=新inode存路径(可跨FS,源删则悬空)
fork()+COWfork 只复制页表(KB级),父子共享物理页标记只读;写时才拷贝该页,exec() 后大部分页无需拷贝
malloc 延迟分配malloc 只分配虚拟地址,首次访问触发 Minor Page Fault 才分配物理页
Redis bgsavefork 子进程 + COW 遍历数据快照写磁盘,父进程继续服务

🧠 助记汇总

口诀含义
进程=资源分配,线程=调度执行进程 vs 线程核心区别
互持循不 (互斥/持有等待/循环等待/不可抢占)死锁四必要条件
排序申请破循环最常用死锁预防:资源编号递增申请
VPN→TLB→页表→PFN虚拟地址翻译链路
OPT不可实现,Clock实际主流页面置换选型
sendfile=不过用户空间零拷贝核心
红黑树+就绪链表+回调epoll 三件套
top→top -Hp→printf hex→jstackCPU飙高排查四步

✅ 自测清单

#问题你能说出...
1进程 vs 线程6 个维度对比 + Linux 下线程本质
2进程调度FCFS/SJF/RR/MLFQ 对比 + MLFQ 降级+Boost 机制
3IPC 方式7 种方式 + 为什么共享内存最快
4死锁四必要条件 + 四处理策略 + 银行家算法思路
5虚拟内存四大好处 + MMU+页表翻译流程
6分段/分页/TLB外部碎片vs内部碎片 + TLB 命中/未命中流程
7页面置换OPT/FIFO/LRU/Clock 对比 + Belady 异常
8零拷贝sendfile vs mmap 流程图 + Kafka 如何用
9epoll三个 API + 红黑树/就绪链表/回调 + LT vs ET
10CPU 排查四步法完整命令 + 常见原因对应栈特征

💡 首次全部过一遍 → 第2天只过答不上来的 → 第4天再复习 → 面试前一天最后扫一遍