操作系统(OS)是什么
操作系统 是管理计算机硬件与软件资源的系统软件,是计算机最底层、最核心的软件,也是用户和计算机硬件之间的桥梁。
操作系统的主要作用
管理硬件资源统一管理 CPU、内存、硬盘、显卡、键盘鼠标、打印机等,让硬件协调工作。
管理软件与进程控制程序的运行、切换、结束,防止多个程序互相冲突。
提供用户接口让普通人可以通过桌面、窗口、鼠标操作电脑,而不用直接对硬件发指令。
文件管理负责文件的存储、读取、删除、复制,组织磁盘上的所有数据。
设备驱动与控制让硬件和软件能 "沟通",比如让系统识别 U 盘、显卡、网卡。
安全与权限管理控制用户权限、防止程序非法访问资源,保护系统稳定。
内核态与用户态的区别
先一句话概括:内核态是操作系统核心运行的特权模式,用户态是普通应用程序运行的受限模式。
- 权限不同
内核态(Kernel Mode) 拥有最高权限,可以直接访问所有硬件、全部内存、执行所有 CPU 指令。
用户态(User Mode) 只有受限权限,不能直接操作硬件,不能访问内核内存,很多敏感指令禁止执行。
- 访问范围不同
内核态:可访问整个物理内存、所有 I/O 设备。
用户态:只能访问自己进程的虚拟地址空间,不能越界访问。
- 运行主体不同
内核态:操作系统内核、驱动程序。
用户态:QQ、浏览器、游戏、编辑器等所有应用程序。
- 切换开销
用户态 → 内核态:需要系统调用、中断,有一定开销。
内核态 → 用户态:执行返回即可。
- 稳定性影响
内核态出错:直接导致系统崩溃、死机。
用户态出错:一般只导致当前程序崩溃,系统不受影响。
为什么要区分内核态与用户态
核心目的只有一个:保证系统安全、稳定,防止程序乱来。
具体原因:
防止恶意 / 错误程序破坏系统应用如果能随便改内存、关硬件、删系统文件,电脑会瞬间崩溃。
保护关键资源比如 CPU 调度、内存分配、硬盘读写、网卡数据,必须由操作系统统一管理,避免冲突。
实现多任务与隔离每个程序在用户态独立运行,互不干扰,一个程序崩了不影响其他程序和系统。
提供统一接口应用不用直接操作硬件,通过系统调用请求内核完成,简化开发,也方便移植。
极简背诵版
内核态:高权限,运行操作系统,可直接访问硬件与全部内存,出错易导致系统崩溃。
用户态:低权限,运行应用程序,受限访问,出错一般只影响自身。
区分目的 :保护系统安全稳定,实现资源隔离与统一管理,防止程序非法操作硬件与内存。
系统调用是什么
系统调用 是应用程序(用户态)请求操作系统内核(内核态)提供服务的接口 。简单说:程序想干权限不够的事,就通过系统调用喊内核帮忙。
典型场景:
- 读写文件
- 申请内存
- 网络收发数据
- 创建进程 / 线程
- 打印、操作硬件等
本质:用户态 → 内核态的一次切换 + 内核函数执行。
系统调用 vs 普通函数调用
运行级别不同
系统调用 :用户态 → 内核态,涉及特权切换
普通函数调用 :全程在用户态,不切换级别
中断、异常、系统调用三者区别
中断 :硬件发来的异步信号,打断 CPU 当前工作。回到被打断的指令继续执行
异常 :指令执行出错产生的同步事件。终止程序或修复后重试
系统调用 :程序主动通过特殊指令进入内核请求服务。执行完返回用户态继续
让 CPU 从用户态陷入内核态,执行内核处理程序
并发与并行的区别
并发(Concurrency): 一个 CPU 核心,轮流执行 多个任务,同一时刻只有一个任务在运行
并行(Parallelism): 多个 CPU 核心,真正同时 执行多个任务,同一时刻多个任务都在运行
多道程序设计
多道程序设计是在内存中同时存放多个相互独立的程序,使之在管理程序控制下交替执行,共享系统中的各种软硬件资源,以提高 CPU 利用率和系统效率的技术。
进程与线程的区别
进程是资源分配 单位,线程是CPU 调度单位
进程有独立地址空间 ,线程共享进程资源
进程切换开销大 (要切换地址空间、页表等),线程切换开销**小(**只切换上下文,不换地址空间)
进程间互不影响,线程崩溃会导致整个进程崩溃
进程通信复杂(管道、消息队列、共享内存、信号等),线程通信直接读写全局变量即可,简单
进程的 5 种状态
**新建态(New)**进程刚被创建,还未提交给调度程序。
就绪态(Ready) 进程已获得除 CPU 外的所有资源,等待被调度运行。
**运行态(Running)**进程正在 CPU 上执行。
阻塞态(Blocked / Wait) 进程因等待某事件(I/O、信号、资源)而暂时无法运行,主动放弃 CPU。
**终止态(Terminated)**进程执行结束或被终止,等待系统回收资源。
进程的状态转换
- 就绪 → 运行
- 发生条件:进程调度(调度程序选中它)
- 运行 → 就绪
- 发生条件:时间片用完被更高优先级进程抢占
- 运行 → 阻塞
发生条件:进程主动等待某事件
等待 I/O
申请资源失败
执行
sleep、wait等
- 阻塞 → 就绪
发生条件:等待的事件完成
I/O 结束
资源可用
收到信号
- 新建 → 就绪
进程初始化完成,进入就绪队列。
- 运行 → 终止
进程执行完毕、正常退出或被杀死。
三、一句话背诵版
就绪 ↔ 运行:调度选中 / 时间片到
运行 → 阻塞:等事件(I/O/ 资源)
阻塞 → 就绪:事件完成
只有就绪态能到运行态,阻塞态不能直接上 CPU
PCB 是什么
PCB(Process Control Block)进程控制块 是操作系统描述和管理进程 的核心数据结构,是进程存在的唯一标志。
简单记:操作系统靠 PCB 认识进程、管理进程。
PCB 包含哪些内容
进程标识信息进程 ID(PID)、父进程 ID、用户 ID 等
进程状态就绪、运行、阻塞等
CPU 现场信息程序计数器 PC、通用寄存器、程序状态字 PSW 等(进程切换时保存 / 恢复用)
进程调度信息优先级、等待时间、已运行时间等
内存管理信息页表、段表、地址空间等
资源信息打开的文件、占用的 I/O 设备等
记账信息CPU 使用时间、账号等
极简背诵版
PCB 是进程控制块 ,是进程存在的标志,保存进程标识、状态、CPU 现场、调度信息、内存信息、资源信息等,用于操作系统对进程进行管理和切换
进程通信方式
- 管道(Pipe)
分为无名管道 和有名管道(FIFO)
无名管道:亲缘进程(父子 / 兄弟)使用
有名管道:可用于任意进程
特点:
半双工通信(单向)
面向字节流
数据临时存放,读完就没
- 消息队列(Message Queue)
内核维护的消息链表
进程按类型收发消息
特点:
全双工
消息有格式、有优先级
不随进程消失,内核持续存在
- 共享内存(Shared Memory)
多个进程共享同一块物理内存区域
特点:
速度最快的 IPC
无需数据拷贝
必须配合信号量实现同步互斥
- 信号量(Semaphore)
本质是计数器 ,用于同步与互斥
不是用来传数据,而是控制访问
常见:
二元信号量(互斥锁)
计数信号量(限制并发数)
- 套接字(Socket)
可用于同一主机 或不同主机间进程通信
网络通信的标准方式
面向连接(TCP)或无连接(UDP)
一句话总结(背诵版)
管道:简单单向,亲缘 / 任意进程通信
消息队列:内核消息链表,可按类型收发
共享内存:速度最快,需信号量同步
信号量:实现同步互斥,不传输数据
套接字:支持跨主机网络通信
线程同步方式
- 互斥锁(Mutex)
保证同一时刻只有一个线程进入临界区
特点:谁加锁谁解锁,用于互斥访问
- 自旋锁(Spinlock)
线程拿不到锁时循环忙等,不进入阻塞
适合:锁持有时间很短、多核场景
- 信号量(Semaphore)
计数器,允许多个线程同时访问
二元信号量 = 互斥锁
计数信号量:控制并发数量
- 条件变量(Condition Variable)
配合互斥锁使用
线程等待某个条件满足时阻塞等待,避免轮询浪费 CPU
典型:生产者--消费者模型
- 读写锁(RWMutex)
区分读操作 和写操作
读共享、写独占
适合读多写少场景
- 屏障(Barrier)
让一组线程都到达后再一起继续执行
用于多线程分步协作
极简背诵版
线程同步方式:互斥锁、自旋锁、信号量、条件变量、读写锁、屏障 。核心作用:保证线程安全,协调执行顺序,避免竞态条件。
协程 vs 线程
- 协程 :由程序 / 用户态框架 调度,内核完全不知道,程序自己调度,只在用户态切换,开销极小、栈很小(KB 级),可轻松创建百万级,、无线程安全问题。
- 线程 :由操作系统内核 调度,属于内核态调度,切换要陷入内核、保存上下文,开销大,有独立栈,占用内存大(MB 级), 多核可并行,需同步机制。
孤儿进程、僵尸进程、守护进程是什么
- 孤儿进程(Orphan Process)
定义:父进程先退出,子进程还在运行,这个子进程就叫孤儿进程。
归宿 :被 init 进程(PID=1) 收养,由 init 负责回收。
危害 :无危害,系统会正常处理。
- 僵尸进程(Zombie Process)
定义 :子进程先结束,但父进程没有调用 wait () /waitpid () 回收其 PCB 信息,子进程变成僵尸。
特点 :进程已死,但是 PCB 还占着进程号(PID)。
危害:大量僵尸会耗尽 PID,导致无法创建新进程。
解决:
父进程调用 wait 回收
杀死父进程,让 init 收养并清理
- 守护进程(Daemon Process)
定义 :运行在后台、不受终端控制、长期运行的系统服务进程。
特点:
脱离终端
父进程是 init
开机自启,默默提供服务
例子:httpd、nginx、sshd 等服务。
一句话背诵版(考试专用)
孤儿进程 :父死子存,被 init 收养,无危害。
僵尸进程 :子死父不收,PCB 残留,占用 PID 有害。
守护进程 :后台长期运行、脱离终端的系统服务进程。
什么是死锁
死锁 :指多个进程在执行过程中,因互相持有对方需要的资源、又不释放自己的资源 ,而造成的一种互相等待、永远无法推进的僵局。若无外力干涉,这些进程将一直阻塞下去。
死锁的四个必要条件
这四个条件必须同时成立,才会产生死锁,缺一不可:
互斥条件资源一次只能被一个进程占用,其他进程必须等待。
请求与保持条件 进程已经持有至少一个资源,又去申请新资源,且不释放已占有的资源。
不可剥夺条件 进程已获得的资源,在未使用完之前,不能被强行剥夺,只能由进程自己释放。
循环等待条件 多个进程形成资源请求的环形链,比如:P1 等 P2,P2 等 P3,P3 等 P1。
三、极简背诵版
死锁:多个进程互相持有并等待资源,陷入永久阻塞。
四个必要条件 :互斥、请求保持、不可剥夺、循环等待。
死锁预防(Prevention)
思想:破坏四个必要条件中的任意一个,从根源杜绝死锁。
破坏互斥条件让资源可共享(如只读文件),但很多资源无法做到。
破坏请求与保持 进程运行前一次性申请所有资源,要么全分配,要么不分配。
破坏不可剥夺条件 进程申请新资源失败时,主动释放已占资源。
破坏循环等待 给所有资源统一编号,进程必须按序号递增申请资源。
死锁避免(Avoidance)
思想:不强行限制,而是动态判断,小心分配资源,不让系统进入不安全状态。
典型算法:银行家算法
每次分配前检查:分配后系统是否仍安全
安全:存在一个进程序列,可顺利执行完毕
不安全:可能发生死锁
死锁检测(Detection)
思想:不预防、不避免,允许死锁发生,但定期检测是否出现死锁。
方法:
构建资源分配图
检查图中是否存在环
有环且资源不可抢占,则死锁
死锁解除(Recovery)
思想:检测到死锁后,强行打破僵局。
资源剥夺法从某个进程强行抢走资源给死锁进程。
进程撤销法
撤销所有死锁进程(彻底但代价大)
逐个撤销,直到死锁解除
进程回退法让进程回滚到之前状态,释放资源。
极简背诵版
预防:破坏四个条件,静态杜绝。
避免:银行家算法,动态保持安全。
检测:看资源图是否有环。
解除:抢资源、杀进程、回滚。
银行家算法原理
一句话核心
银行家算法是死锁避免算法 ,核心思想:每次分配资源前,先检查分配后系统是否仍处于安全状态。 安全就分配,不安全就拒绝,从而避免死锁。
- 基本概念
安全状态 存在一个进程序列(安全序列),按照这个顺序给每个进程分配资源,所有进程都能顺利执行完毕。
不安全状态 不存在这样的序列,可能导致死锁。
算法步骤(原理)
检查本次请求是否超过进程声明的最大值
检查请求是否超过当前系统剩余可用资源
假设先分配资源,修改相应数据结构
检查分配后系统是否仍安全
安全 → 正式分配;不安全 → 撤销假设,让进程等待
用到的四个矩阵(背名字即可)
Available 系统可用资源
Max 进程最大需求
Allocation 已分配资源
Need 剩余需求 = Max - Allocation
极简背诵版
银行家算法用于死锁避免 ,通过检查系统是否处于安全状态来决定是否分配资源,保证系统始终有一个安全序列,从而不进入死锁。
常见进程调度算法
- FCFS 先来先服务
思想:谁先来谁先运行,排队执行
抢占:非抢占式
优点:简单、公平、好实现
缺点:长作业堵后面,短作业等待久;不利于交互
吞吐量:低
响应时间:长,不稳定
饥饿:无
- SJF 短作业优先 / SRTF 短剩余时间优先
思想:优先运行执行时间最短的作业
SJF:非抢占
SRTF:抢占式(新短作业到来可抢占)
优点 :平均等待时间最短,吞吐量最高
缺点 :需预知运行时间;长作业可能饥饿
吞吐量:最高
响应时间:短作业很快,长作业很慢
饥饿 :会饥饿(长作业一直得不到运行)
- 优先级调度
思想:按优先级高低运行
可抢占 / 不可抢占
优点:灵活,可优先重要任务
缺点 :低优先级任务可能饥饿
吞吐量:取决于优先级设置
响应时间:高优先级快,低优先级慢
饥饿 :会饥饿
解决:动态优先级 / 老化(等待越久优先级越高)
- 时间片轮转 RR
思想:每个进程轮流运行一个时间片
抢占:抢占式(时间片到就切换)
优点 :公平,响应时间快,适合交互式系统
缺点:时间片太小→切换开销大;太大→退化成 FCFS
吞吐量:中等
响应时间 :较好、均匀
饥饿:无
- 多级反馈队列
思想:多个优先级队列,优先级从高到低;新进程进高优先级,用完时间片降级;越短作业越快完成。
抢占:抢占式
优点:综合性能好,兼顾短作业、交互、长作业
缺点:算法复杂
吞吐量:较高
响应时间:好
饥饿:可能饥饿(可加老化机制避免)
| 算法 | 抢占? | 吞吐量 | 响应时间 | 饥饿? | 特点 |
|---|---|---|---|---|---|
| FCFS | 非抢占 | 低 | 差 | 否 | 简单公平 |
| SJF/SRTF | 均可 | 最高 | 短作业优 | 会 | 平均等待最短 |
| 优先级调度 | 均可 | 不定 | 高优快 | 会 | 灵活但可能饥饿 |
| RR 轮转 | 抢占 | 中 | 好 | 否 | 适合交互 |
| 多级反馈队列 | 抢占 | 较高 | 好 | 可避免 | 综合最优 |
逻辑地址 vs 物理地址
一、概念
逻辑地址(相对地址) 程序员视角、程序编译后生成的地址,从 0 开始编址,由 CPU 执行指令时产生。也叫:虚拟地址。
物理地址(绝对地址) 内存硬件真实的地址,对应实际物理存储单元,是最终送到地址总线上的地址。
二、核心区别
产生方不同
逻辑地址:CPU 生成、程序看到
物理地址:内存硬件实际地址
是否唯一
逻辑地址:每个进程独立,可以重复
物理地址:整个内存唯一,不能重复
地址空间
逻辑地址:每个进程有独立虚拟地址空间
物理地址:共用一个物理内存空间
转换关系
逻辑地址 →(MMU 硬件)→ 物理地址
用户程序只使用逻辑地址,完全不知道物理地址
三、一句话背诵版
逻辑地址:程序使用的虚拟地址,相对、独立、需转换。
物理地址:内存真实硬件地址,绝对、唯一、直接寻址。
由 MMU(内存管理单元) 完成逻辑地址到物理地址的转换。
虚拟内存 & 作用
什么是虚拟内存
虚拟内存 是利用硬盘空间 模拟出的一块逻辑内存,让系统看起来拥有比实际物理内存更大的地址空间。本质是:请求调页 + 逻辑地址空间与物理地址空间分离。
简单理解:把一部分硬盘当内存用,让程序以为内存很大。
核心作用
扩大地址空间让程序可以使用比物理内存更大的地址空间,运行更大的程序。
内存共享不同进程可以共享虚拟内存区域,实现进程通信、共享库。
内存保护每个进程有独立虚拟地址空间,互不干扰,防止越界访问。
提高内存利用率 只把当前需要的页面装入内存,不用的放硬盘,实现按需调页。
简化程序链接与加载程序编译时统一从 0 地址开始,不用关心实际物理位置。
一句话极简版
虚拟内存是操作系统利用硬盘模拟的逻辑内存 ,作用是扩大地址空间、实现内存隔离与保护、提高内存利用率。
分页与分段的区别
一、基本概念
分页(Paging) 把进程地址空间按固定大小的页(Page)划分,内存也分成同样大小的物理块(页框)。
分段(Segmentation) 按程序逻辑意义 划分成段(代码段、数据段、栈段等),每段长度不固定。
二、核心区别
- 划分单位不同
分页:固定大小,是物理单位,对用户不可见
分段:长度不固定,是逻辑单位,对用户可见
- 目的不同
分页:为了方便内存管理、提高内存利用率,减少外部碎片
分段:为了满足程序逻辑、方便共享与保护
- 地址结构
分页:页号 + 页内偏移
分段:段号 + 段内偏移
- 碎片问题
分页:有内部碎片(一页最后一点空间用不完),无外部碎片
分段:有外部碎片(空闲区太小无法分配),无内部碎片
- 共享与保护
分页:不方便,因为页不对应逻辑意义
分段:非常方便,可按段共享、按段设置权限
- 扩展性
分页:页大小固定,不易扩展
分段:段可动态增长,易于扩展
三、一句话背诵版
分页:固定大小、物理划分、有内碎无外碎、不便共享
分段:变长逻辑单位、有外碎无内碎、便于共享与保护
TLB 是什么
TLB(Translation Lookaside Buffer)快表 是一种高速缓冲存储器 ,专门存放最常用的页表项(页号→物理块号),属于 MMU 的一部分。
简单理解:页表的高速缓存,避免每次访存都查内存里的页表。
作用
加速地址转换先查 TLB,命中就直接得到物理地址,不用访问页表。
减少访存次数不使用快表:访存 2 次(查页表 + 访问数据)使用快表:命中只需访存 1 次
提高 CPU 访存效率大幅降低虚拟地址转物理地址的开销。
工作流程(极简)
给出逻辑地址 → 拆成页号 + 页内偏移
先查 TLB
命中:直接得到物理块号 → 形成物理地址
未命中:查内存中的页表 → 再把该页表项写入 TLB
一句话背诵版
TLB 是页表的高速缓存(快表) ,用于加快虚拟地址到物理地址的转换速度,减少访存开销,提高运行效率。
页面置换算法
- OPT 最优置换算法
思想 :置换未来最久不使用的页面
特点 :缺页率最低,理论最优
是否可实现:不可实现(无法预知未来)
抖动 / 异常:无
用途:仅作为衡量其他算法的标准
- FIFO 先进先出
思想:先进入内存的页面先淘汰
特点:最简单
异常 :会出现Belady 异常→ 物理块增加,缺页率反而上升
抖动:可能
是否常用:不常用
- LRU 最近最少使用(最常考)
思想 :置换最近最久未使用的页面
特点:性能接近 OPT,实际效果很好
实现:链表、栈、时钟
异常 :无 Belady 异常
是否常用:非常常用(Linux、Windows 都用类似思想)
- LFU 最少使用
思想 :置换访问次数最少的页面
特点 :关注使用频率,不关注时间
缺点:历史频繁使用但现在不用的页面很难淘汰
异常:无
适用:访问模式稳定的场景
- Clock 时钟算法(近似 LRU)
思想:循环队列 + 使用位(0/1)遇到使用位 1 → 置 0,继续走遇到使用位 0 → 置换
别称:二次机会算法
特点:开销小,效果接近 LRU
是否常用:非常常用(Linux 实际在用)
| 算法 | 核心 | 优点 | 缺点 | 是否常用 |
|---|---|---|---|---|
| OPT | 未来最久不用 | 最优 | 不可实现 | 否 |
| FIFO | 先进先出 | 简单 | Belady 异常 | 否 |
| LRU | 最近最久未用 | 效果好 | 开销稍大 | 是 |
| LFU | 访问次数最少 | 适合稳定访问 | 历史数据干扰 | 一般 |
| Clock | 使用位,二次机会 | 开销小、近似 LRU | 精度略低于 LRU | 是 |
一句话速记
OPT:理想最优,无法实现
FIFO:简单,会出现 Belady 异常
LRU:看最近使用,实际最好用
LFU:看访问次数
Clock:近似 LRU,开销低,系统常用
什么是抖动(Thrashing)
抖动(颠簸) :系统频繁进行页面置换 ,刚换出的页面马上又要被访问,不得不立刻换入,CPU 大部分时间都在换页,真正执行任务的时间极少,系统效率急剧下降。
一句话:刚换出去又要换进来,反复折腾,系统卡死。
二、产生原因
进程分配的物理页框太少进程工作集(当前需要的页面)大于分配到的内存空间,频繁缺页。
多道程序度太高内存中进程太多,每个进程分到的页框极少,缺页率暴增。
页面置换算法不合理频繁置换马上就要用到的页面。
局部性原理失效程序访问内存跳跃性大,缺页严重。
根本原因: 进程的缺页率过高,页面置换开销远大于程序执行开销。
三、解决抖动的方法
减少多道程序度,减少内存中并发进程数
为进程增加分配的物理页框
选择更好的置换算法
利用工作集模型,按工作集分配内存
极简背诵版
抖动:系统频繁页面置换,CPU 大量时间用于换页,效率极低。
原因:进程页框太少、多道程序度过高、缺页率过高。
缺页中断
一、定义
缺页中断 :CPU 要访问的页面不在物理内存中,而是在磁盘交换区,此时 CPU 触发的中断就叫缺页中断。
操作系统收到后,会把需要的页面从磁盘调入内存,再让指令重新执行。
二、简单流程
访问逻辑地址,发现页面不在内存
触发缺页中断
操作系统选择一个页面置换出去(如果内存满)
把缺的页面从磁盘读入内存
更新页表,重新执行刚才的指令
三、一句话背诵版
缺页中断是要访问的页面不在内存 时触发的中断,操作系统负责将页面从磁盘调入内存,使程序继续执行。
内部碎片 vs 外部碎片
一、内部碎片(Internal Fragmentation)
定义 :分配给进程的内存空间比实际需要大 ,多余的那部分浪费在分区内部,无法被其他进程使用。
产生场景:
分页管理
固定分区分配
特点:在分区内部,不可利用
二、外部碎片(External Fragmentation)
定义 :内存中存在许多小的空闲分区 ,每个都太小无法分配给新进程,但总容量足够,这些空闲区在分区外部。
产生场景:
分段管理
动态分区分配
特点:分散在各个分区之间,无法利用
三、一句话总结
内部碎片:分给你的空间用不完,浪费在里面
外部碎片:空间有但太碎,没法分给新进程
四、快速对应
分页 → 内部碎片
分段 → 外部碎片
紧凑(拼接) 可以解决外部碎片
文件的逻辑结构 vs 物理结构
一、逻辑结构(用户视角)
用户看到的文件组织形式,与存储无关。
- 无结构文件(流式文件)
字节流,无内部结构
例:文本文件、二进制文件
- 有结构文件(记录式文件)
由若干记录组成
常见:
顺序文件
索引文件
索引顺序文件
二、物理结构(操作系统 / 磁盘视角)
文件在磁盘上的实际存放方式。
- 连续分配
磁盘上连续存放
优点:顺序访问快、随机访问快
缺点:文件不易扩展、产生外部碎片
- 链接分配
离散存放,用指针链接
优点:无碎片、易扩展
缺点:只能顺序访问,不能随机访问;指针占空间
- 索引分配
建索引块,记录盘块号
优点:支持随机访问、易扩展
缺点:索引块占空间,小文件浪费
极简背诵版
逻辑结构:用户看到的结构,分流式、记录式。
物理结构 :磁盘实际存储方式,分连续、链接、索引三种。
连续、链接、索引分配区别
- 连续分配
特点 :文件在磁盘上占连续的盘块
优点:
顺序访问、随机访问都很快
寻道时间短
缺点:
易产生外部碎片
文件不易扩展
创建时需预先知道大小
- 链接分配
特点 :盘块离散,用指针串起来
优点:
无碎片,磁盘利用率高
文件易扩展
缺点:
只能顺序访问,不能随机访问
指针占空间,可靠性差
- 索引分配
特点 :单独建立索引块,记录所有盘块号
优点:
支持随机访问
易于扩展,无碎片
缺点:
索引块额外开销
小文件浪费空间
一句话速记
连续:连续存放,速度快,有碎片、难扩展
链接:指针相连,无碎片,只能顺序访问
索引:索引块记录位置,支持随机访问,有索引开销
磁盘调度算法
- FCFS 先来先服务
思想:按请求到达顺序依次访问
优点:简单、公平
缺点:平均寻道时间长,效率低
适用:请求很少的场景
- SSTF 最短寻道时间优先
思想 :每次找离当前磁头最近的请求
优点:平均寻道时间明显短于 FCFS
缺点 :会产生饥饿(远离磁头的请求长期不响应)
是否公平:不公平
- SCAN 电梯算法
思想 :像电梯一样,朝一个方向移动,处理完该方向所有请求再反向
优点 :性能好,不会饥饿,寻道时间短
特点:双向扫描
适用:请求密集的系统
- CSCAN 循环扫描
思想 :只单向扫描 ,到头直接快速返回起点,不处理回程请求
优点:响应时间更均匀,比 SCAN 更适合循环请求
缺点:平均寻道长度略大于 SCAN
特点:单向循环,无反向处理
一句话速记(背诵版)
FCFS:排队来,简单但慢
SSTF:找最近,快但会饥饿
SCAN:电梯来回走,不饥饿
CSCAN:单向循环走,响应均匀
软链接 vs 硬链接
- 本质区别
硬链接(Hard Link) 与原文件共用同一个 inode 节点 ,相当于文件的别名。
软链接(Soft Link / 符号链接 Symbolic Link) 是一个独立的小文件,里面存放原文件的路径 ,相当于快捷方式。
- 核心区别
(1)是否依赖原文件
硬链接:原文件删除后,链接依然可用,数据还在。
软链接:原文件删除后,软链接失效(变成坏链接)。
(2)能否跨文件系统 / 分区
硬链接 :不能跨分区,只能在同一文件系统。
软链接 :可以跨分区、跨磁盘、跨主机。
(3)能否作用于目录
硬链接 :不支持链接目录(防止循环引用)。
软链接 :可以链接目录。
(4)inode 与文件大小
硬链接 :与原文件 inode 相同,大小一样。
软链接 :有自己独立的 inode ,大小是路径字符串长度。
(5)计数影响
硬链接 :创建会使文件链接计数 +1。
软链接:不影响原文件链接计数。
一句话背诵版
硬链接:同 inode、不依赖原文件、不跨区、不连目录。
软链接:独立文件、存路径、跨区、可连目录、依赖原文件。
inode 是什么
inode(索引节点) 是文件系统中用于描述文件属性与存储位置 的数据结构,每个文件有且只有一个 inode,inode 号在同一个文件系统内唯一。
可以理解为:文件的身份证 + 档案信息表。
二、inode 里存了什么
文件类型(普通文件、目录、设备等)
权限(rwx)
所有者、组
文件大小
时间戳(创建、修改、访问时间)
链接数
磁盘块指针(文件数据存在哪些盘块)
**注意:inode 不存文件名!**文件名只在目录项里,目录本质就是 "文件名 → inode 号" 的映射表。
三、作用
唯一标识文件 系统内部不使用文件名,而是用 inode 号识别文件。
记录文件元信息保存除文件名以外的所有文件属性。
定位文件数据通过盘块指针找到文件实际存储在磁盘的哪些位置。
支撑硬链接多个文件名指向同一个 inode,就是硬链接。
极简背诵版
inode:文件系统的索引节点,存储文件元信息与数据位置。
特点:一个文件一个 inode,inode 唯一,不存文件名。
作用:标识文件、管理属性、定位数据、支持硬链接。
I/O 控制方式(程序查询 / 中断 / DMA / 通道)
- 程序查询方式(轮询)
思想:CPU 不断查询 I/O 设备是否就绪,忙等
特点:CPU 与 I/O 串行工作
优点:简单
缺点:CPU 利用率极低,一直浪费
- 中断驱动方式
思想:I/O 就绪后发中断,CPU 再处理
特点:CPU 与 I/O 可并行
优点:CPU 利用率提高
缺点:频繁中断仍消耗 CPU
- DMA 方式(直接内存访问)
思想 :DMA 控制器控制数据直接在内存与 I/O 间传输
特点:仅开始 / 结束时 CPU 干预,传输过程不占用 CPU
优点:大批量 I/O 效率高
缺点:只能简单块传输,控制能力有限
- 通道方式(I/O 通道)
思想 :专门的I/O 处理器执行通道程序,独立控制 I/O
特点:功能更强,可复杂控制
优点:CPU 解放最彻底,并行度最高
缺点:硬件复杂
一句话速记
查询:CPU 死等,利用率最低
中断:I/O 好了叫 CPU,利用率提升
DMA:内存与 I/O 直传,CPU 少参与
通道:专门 I/O 处理器,CPU 最轻松
递进关系
程序查询 → 中断 → DMA → 通道 CPU 干预越来越少,I/O 并行度越来越高
五种 I/O 模型对比
- 阻塞 I/O(Blocking IO)
特点:调用
read后,一直等,直到数据就绪并拷贝完成阶段:
等待数据就绪:阻塞
内核→用户拷贝:阻塞
优点:简单
缺点:并发差,一个连接占一个线程
- 非阻塞 I/O(Non-blocking IO)
特点:调用
read没数据就立即返回,不阻塞需不断轮询(轮询
recv)阶段:
等待数据:不阻塞(立刻返回)
拷贝数据:阻塞
优点:不卡死线程
缺点:频繁轮询消耗 CPU
- I/O 多路复用(IO Multiplexing)
代表:select / poll / epoll
特点:一个线程监听多个描述符,哪个就绪处理哪个
阶段:
阻塞在 select/epoll 上
数据就绪后调用 read:仍会阻塞拷贝
优点:高并发,单线程处理大量连接
缺点:数据拷贝阶段仍阻塞,不算真正异步
- 信号驱动 I/O(Signal Driven IO)
特点:注册信号,数据就绪时内核发信号通知
阶段:
等待数据:不阻塞
收到信号再去 read:拷贝阶段阻塞
优点:不轮询、不阻塞等待
缺点:信号量大时易混乱,实际用得少
- 异步 I/O(Asynchronous IO)
代表:POSIX aio_ 系列,Windows IOCP*
特点:全程不阻塞,内核完成所有操作后通知进程
阶段:
等待数据:不阻塞
内核→用户拷贝:不阻塞
真正的完全异步
优点:性能最高,CPU 利用率最好
缺点:实现复杂,操作系统支持不一
一句话区分(超级好记)
阻塞 I/O:一直等数据
非阻塞 I/O:没数据就走,反复问
多路复用:一个线程盯多个 socket
信号驱动:内核发信号告诉我好了
异步 I/O:内核全部做完再通知,全程不阻塞
关键总结(必背)
前 4 种都是同步 I/O :因为数据拷贝阶段都会阻塞
只有 异步 I/O 是真正异步
实际高并发服务器主流:I/O 多路复用(epoll)
零拷贝(Zero Copy)
一、定义
零拷贝 是指在 I/O 传输过程中,避免数据在用户缓冲区与内核缓冲区之间重复拷贝,减少 CPU 参与,从而大幅提升传输效率。
核心目标:减少数据拷贝次数 + 减少用户态 / 内核态切换次数
二、传统 I/O 问题(以文件发送到网络为例)
硬盘 → 内核读缓冲区
内核 → 用户缓冲区
用户 → 内核 Socket 缓冲区
内核 → 网卡
共 4 次拷贝 + 多次上下文切换,CPU 开销大。
三、零拷贝怎么做
常用方式:
mmap:内存映射,让用户空间直接访问内核缓冲区,省去一次拷贝
sendfile:系统调用,数据直接在内核空间从文件缓冲区传到 Socket 缓冲区
DMA 辅助 + 避免 CPU 拷贝
最终可做到:数据只在硬盘→内核→网卡之间传输,完全不经过 CPU 拷贝
四、作用
大幅提高文件传输效率(如 Web 服务器、消息队列)
降低 CPU 占用
减少用户态 / 内核态切换
一句话背诵版
零拷贝是避免数据在用户态与内核态之间重复拷贝 的 I/O 优化技术,通过减少拷贝与上下文切换,大幅提升数据传输效率、降低 CPU 开销。
缓冲区的作用
缓解 CPU 与 I/O 设备速度不匹配CPU 速度极快,I/O 设备很慢,缓冲区用来平滑数据传输,避免 CPU 长时间等待。
减少对设备的 I/O 操作次数数据先攒满缓冲区再一次性读写,降低频繁访问设备的开销。
实现 CPU 与 I/O 设备并行工作设备往缓冲区写数据时,CPU 可以去做别的任务,提高系统并发效率。
提高数据传输效率成块传输比单字节传输效率高得多。
实现数据的暂存与解耦让生产者和消费者速度不一致时仍能正常工作。
极简背诵版
缓冲区用于匹配高速 CPU 与低速 I/O 设备速度差异,减少 I/O 次数、提高传输效率、实现并行工作。
设备驱动程序作用
设备驱动程序是操作系统与 I/O 设备之间的接口软件,对上层隐藏硬件细节,实现设备控制。
主要作用:
接收上层软件发来的抽象 I/O 命令,转化为具体硬件操作。
直接控制硬件:向设备寄存器发命令、启动 / 停止设备、检查设备状态。
处理设备发出的中断,进行中断处理。
对上层屏蔽硬件差异,操作系统只需统一接口调用驱动。
完成数据传输与缓冲控制,保证数据正确交互。
极简背诵版
设备驱动程序是OS 与硬件的接口 ,负责将抽象指令转为硬件操作、控制设备、处理中断、屏蔽硬件细节。
为什么要有虚拟内存
扩充内存容量让程序可以使用比物理内存更大的地址空间,运行更大的程序。
实现进程地址空间隔离 每个进程拥有独立的虚拟地址空间,互不干扰,提高系统安全性与稳定性。
方便内存管理,减少碎片 采用分页 / 分段机制,离散分配内存,有效解决外部碎片问题。
实现内存共享与保护方便共享代码段、库文件;并通过权限控制实现内存访问保护。
简化程序编译与加载程序统一从虚拟地址 0 开始编址,不用关心实际物理内存位置。
实现请求调页 / 调段,提高内存利用率只将当前需要的部分装入内存,不需要的放在磁盘,节约物理内存。
极简背诵版
虚拟内存是为了:扩大地址空间、实现进程隔离与保护、提高内存利用率、简化编程与加载。
多线程一定比单线程快吗
不一定,甚至很多时候更慢。
什么时候多线程更快?
任务是 I/O 密集型(网络、磁盘、等待)
线程在等待时,CPU 可以切换去做别的事
多核 CPU 下,真正并行计算
什么时候多线程更慢?
线程切换开销大切换需要保存 / 恢复上下文,频繁切换反而浪费 CPU
线程间竞争与同步加锁、解锁、等待会造成串行化,甚至比单线程还慢
计算密集型任务单核下多线程 = 频繁切换 + 无并行 → 更慢
线程创建 / 销毁开销大量短生命周期线程,开销远大于收益
结论(背诵版)
多线程不一定比单线程快。
I/O 密集型、多核并行 → 更快
频繁切换、竞争锁、计算密集、单核 → 更慢
进程切换 vs 线程切换 开销区别
- 根本区别
进程切换 :切换两个不同进程
线程切换 :切换同一进程内的两个线程
开销差异(核心)
地址空间是否切换
进程切换 :要切换页表、虚拟地址空间 ,刷新 TLB,开销很大
线程切换 :共用同一地址空间,不换页表、不刷新 TLB ,开销小很多
资源是否共享
进程切换:需保存 / 恢复更多上下文(页表、打开文件、信号等)
线程切换:只需保存栈、寄存器、程序计数器等少量上下文
Cache / TLB 影响
进程切换:Cache、TLB 基本失效,重新缓存
线程切换:地址空间不变,Cache 基本有效
一句话总结
线程切换远快于进程切换。 进程切换要换地址空间、刷新 TLB;线程切换只换上下文,不换地址空间。
极简背诵版
进程切换:切换地址空间、刷新 TLB,开销大。
线程切换:共享地址空间,不刷新 TLB,开销小。
共享内存为什么是最快的进程通信方式
因为共享内存是唯一一种不需要内核参与数据拷贝的通信方式。
核心原因
直接映射同一块物理内存 多个进程的虚拟地址空间直接映射到同一块物理内存 ,进程之间直接读写内存即可通信。
不需要内核缓冲区,零拷贝不像管道、消息队列需要:
- 进程 → 内核缓冲区 → 另一个进程共享内存完全跳过内核拷贝,没有任何复制开销。
系统调用 & 内核干预极少 只在创建、绑定、删除 时调用系统函数,实际读写数据时不需要进入内核态、不发生上下文切换。
速度接近线程间通信本质就是内存级别的直接访问,速度只受内存读写速度限制,是所有 IPC 中最快的。
极简背诵版
共享内存直接让多个进程访问同一块物理内存 ,无需内核拷贝、无数据复制、系统调用少,因此速度最快。
LRU 如何实现
核心思想
LRU(最近最少使用) :淘汰最近最久未使用的数据。
标准实现:哈希表 + 双向链表
双向链表
按访问时间排序
头部:最近刚使用
尾部:最久未使用(优先淘汰)
哈希表(HashMap)
键:数据 key
值:链表节点指针 / 引用
作用:O (1) 快速查找节点
操作流程
访问数据 :查到节点后,把它移到链表头部(标记为最近使用)
插入数据 :直接插入链表头部
缓存满了 :删除链表尾部节点,同时删除哈希表中对应项
时间复杂度
- 查找、插入、删除:均为 O(1)
极简背诵版
LRU 使用 哈希表 + 双向链表 实现:
哈希表保证 O (1) 查找
双向链表维护访问顺序
头部最新,尾部最旧,满了删尾部
系统调用完整流程
流程步骤
用户程序调用库函数 (如
read、write)将系统调用号、参数放入寄存器
执行陷入指令(trap /syscall/int 0x80)
触发软中断,CPU 从用户态 → 内核态
保存用户进程上下文(寄存器、程序计数器等)
根据系统调用号查找系统调用表
执行对应的内核处理函数
执行完毕,设置返回值
恢复用户进程上下文
从内核态返回用户态,继续执行
极简背诵版
用户程序传参
执行陷入指令
用户态切内核态
保存上下文
查调用表、执行内核函数
恢复上下文
返回用户态
一句话速记
用户调用 → 陷入内核 → 保存现场 → 执行内核函数 → 恢复现场 → 返回用户
页面大小过大 vs 过小
- 页面过小
页表变大,占用内存多
缺页中断次数增多,频繁换页,效率低
但内部碎片小,内存利用率高
- 页面过大
页表小,占用内存少
缺页中断少,换页次数少
但内部碎片大,内存浪费严重
磁盘 I/O 传输开销变大
极简背诵版
页面过小:页表大、缺页频繁,但碎片小
页面过大:页表小、缺页少,但内部碎片大、浪费内存
写时复制(Copy-On-Write, COW)
定义
写时复制是一种推迟复制、惰性复制 的优化策略:只有在真正需要修改数据时,才去复制副本;只读时共享同一份数据。
典型场景:Linux fork ()
子进程创建时,并不复制父进程的整个地址空间
父子进程共享同一页框 ,页表设为只读
当任一进程试图写入 时,触发缺页异常
操作系统此时才真正复制一页数据,并改为可写
优点
极大提高
fork速度减少不必要的内存复制与内存浪费
一句话背诵版
写时复制:读时共享,写时复制。只有修改时才真正拷贝,减少复制开销,提升效率。