外观
操作系统 速查卡
🎯 覆盖 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 使可用内存大于物理内存。
四大好处:
- 进程隔离 — 互不访问对方物理内存
- 内存扩展 — 缺页中断 + Swap 实现按需加载
- 简化管理 — 统一虚拟地址布局(0~3G 用户/3G~4G 内核)
- 方便移植 — 程序只用虚拟地址,与物理无关
虚拟地址 = [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)。
| 维度 | select | poll | epoll |
|---|---|---|---|
| fd 上限 | 1024 | 无限 | 无限 |
| 数据结构 | 位图 | 链表 | 红黑树+就绪链表 |
| fd 传递 | 每次全量拷贝到内核 | 同左 | 注册一次(epoll_ctl) |
| 检测方式 | 遍历 O(n) | O(n) | 回调加入就绪链表 O(1) |
| 触发模式 | LT | LT | LT + ET |
epoll_create → 创建红黑树+就绪链表
epoll_ctl → fd 注册到红黑树,绑定回调
epoll_wait → 直接返回就绪链表中的 fdLT 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 <PID>/strace -cp <PID>/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()+COW | fork 只复制页表(KB级),父子共享物理页标记只读;写时才拷贝该页,exec() 后大部分页无需拷贝 |
| malloc 延迟分配 | malloc 只分配虚拟地址,首次访问触发 Minor Page Fault 才分配物理页 |
| Redis bgsave | fork 子进程 + COW 遍历数据快照写磁盘,父进程继续服务 |
🧠 助记汇总
| 口诀 | 含义 |
|---|---|
| 进程=资源分配,线程=调度执行 | 进程 vs 线程核心区别 |
| 互持循不 (互斥/持有等待/循环等待/不可抢占) | 死锁四必要条件 |
| 排序申请破循环 | 最常用死锁预防:资源编号递增申请 |
| VPN→TLB→页表→PFN | 虚拟地址翻译链路 |
| OPT不可实现,Clock实际主流 | 页面置换选型 |
| sendfile=不过用户空间 | 零拷贝核心 |
| 红黑树+就绪链表+回调 | epoll 三件套 |
| top→top -Hp→printf hex→jstack | CPU飙高排查四步 |
✅ 自测清单
| # | 问题 | 你能说出... |
|---|---|---|
| 1 | 进程 vs 线程 | 6 个维度对比 + Linux 下线程本质 |
| 2 | 进程调度 | FCFS/SJF/RR/MLFQ 对比 + MLFQ 降级+Boost 机制 |
| 3 | IPC 方式 | 7 种方式 + 为什么共享内存最快 |
| 4 | 死锁 | 四必要条件 + 四处理策略 + 银行家算法思路 |
| 5 | 虚拟内存 | 四大好处 + MMU+页表翻译流程 |
| 6 | 分段/分页/TLB | 外部碎片vs内部碎片 + TLB 命中/未命中流程 |
| 7 | 页面置换 | OPT/FIFO/LRU/Clock 对比 + Belady 异常 |
| 8 | 零拷贝 | sendfile vs mmap 流程图 + Kafka 如何用 |
| 9 | epoll | 三个 API + 红黑树/就绪链表/回调 + LT vs ET |
| 10 | CPU 排查 | 四步法完整命令 + 常见原因对应栈特征 |
💡 首次全部过一遍 → 第2天只过答不上来的 → 第4天再复习 → 面试前一天最后扫一遍