想象一下,城市图书馆里有位经验丰富的管理员老王。读者报出一个书号,老王的大脑会瞬间回想:“嗯,这本《操作系统导论》上次放在二楼的C区4排。”于是三步并作两步取来。但如果读者报的书号他记不住,就得去翻那本厚达千页的索引目录;翻完发现,这本书居然被移到地下仓库去了——老王就得坐货运电梯下去,花几分钟把书搬上来,同时更新索引卡。你的CPU和内存之间,每时每刻都在上演同样的故事:书号是虚拟地址,书架位置是物理地址,老王的记忆是TLB,索引目录是页表,而地下仓库取书,就是缺页中断。这篇文章将带你完整走一遍这条“寻书”链路,看看一次内存访问从快到慢、从命中到缺页的全部旅程。
理解缺页中断与TLB,是排查系统卡顿、优化数据库缓存命中率、设计高并发服务内存策略的底层基本功——它能让你从“代码会跑”进阶到“知道系统为什么快、为什么慢”。
目录
可视化演示
展示TLB地址翻译查找流程、缺页中断完整处理链路、以及写时复制CoW按需调页机制。
本节配有交互动效(进入视口后自动加载,约 3KB)。
'+_captions.tlb+'
虚拟内存寻址:书号与书架坐标
图书馆里每本书有两套编号:读者查的“标准书号”和书架上实际贴的“位置标签”。一本热销书可以在三楼A区,也可以在临时展台,但标准书号永远不变。操作系统的虚拟内存也是这样——每个进程都拥有一片连续的“虚拟地址空间”,这相当于统一的图书编号;而物理内存是真正的书架,每根内存条上的“物理地址”就是书架坐标。进程不需要关心书到底放在哪个书架上,它只要报出书号,由操作系统负责翻译。
翻译工作由“页表”完成。虚拟地址空间被切成等大的“页”,物理内存被切成同样大小的“页框”或“页帧”。页表就是一张巨大的对照卡,每一条记录一个虚拟页对应哪个物理页框。CPU访问任意一个地址,都要把虚拟地址拆成“虚拟页号 + 页内偏移”,然后查页表拿到页框号,最后拼出物理地址。
老王如果每本书都翻一遍千页索引,读者怕是要等到天黑。所以这里的关键问题是:能不能让“翻索引”这个过程快到让读者无感?答案就是下一节的 TLB。
- 拆分虚拟地址CPU 发出的虚拟地址可拆成高位的虚拟页号和低位的页内偏移,如同把书号拆成“哪个馆、哪个架”和“第几本”。
- 页表翻译页表是系统维护的映射表,输入虚拟页号,输出对应物理页框号,如同索引卡上写着“这本书在三楼C区4排”。
- 拼接物理地址物理地址的高位是页框号、低位是页内偏移。页框号确定“哪个书架”,偏移量确定“书架上第几本”。
TLB快表机制:老王的记忆小本本
老王工作二十年,练就了一项本领:热销书的位置他张口就来。“《三体》?二楼科幻区左数第三本。”至于冷门书,他才去翻索引。这个“张口就来”的记忆,就是 TLB(Translation Lookaside Buffer,翻译后备缓冲器),它是 CPU 内部一块超小的硬件缓存,专门记住最近用过的“虚拟页号 → 页框号”映射。TLB 命中时,地址翻译在一个 CPU 时钟周期内完成,快如闪电;TLB 缺失时,CPU 才不得不去内存里翻多级页表,速度慢一个数量级。
为什么 TLB 的命中率能那么高?靠的是“局部性原理”:程序在一段时间内访问的地址总是聚集在少数几个页面里——循环体反复执行、数组顺序遍历,都让同样的页面被反复访问。就像读者来图书馆通常只奔几个固定书架,老王当然把这几本书的位置记得滚瓜烂熟。所以 TLB 不必很大(一般几十到几千条),只要够装下“当前工作集”就够用了。
但老王记忆再好,也会遇到完全没印象的书——他甚至翻遍索引卡都找不到这本书的登记。这时,真正的“缺页”故事才刚刚开始。
- 命中分支TLB 命中时,CPU 直接拿到页框号,无需访问内存中的页表。h 是命中率,T\_TLB 是一次快表查询时间。
- 缺失分支TLB 缺失时,需要先去页表查询,再访问真正的数据。共花费一次快表查询加一次内存访问时间。
- 加权求和把所有访问按命中与否加权平均,就是一次翻译+取数的期望时间。
缺页异常触发:索引也查不到的书
老王接到借书请求,大脑(TLB)空白,翻索引(页表)时发现这张索引卡是空白的——上面盖着“该书未登记”的红章,或者写着“此书已移至地下仓库”。在操作系统里,这对应页表项的存在位(Present/Valid Bit)为 0。存在位是页表项里最关键的标记:为 1 表示这个虚拟页此刻就住在某个物理页框里;为 0 表示这个页面不在内存中。只要 CPU 发现存在位为 0,就会触发一个异常——缺页中断(Page Fault)。
注意,缺页中断不是所有“查不到”都算。有一种情况是保护位违规:比如一个只读页面被尝试写入(写时复制的触发场景),或者用户态程序碰了内核态页面。这时页表项还在、页面也在内存里,但权限不允许,CPU 同样会陷入异常。这相当于老王查到了书,却被告知“这本书只能阅览,不外借,更不能在上面写字”。此外,进程首次访问一个从未碰过的地址,比如申请了一大块堆内存但还没写入,页表项压根不存在,这属于“未映射页面”,一样会触发缺页。
触发只是开始。缺页中断一旦发生,老王就得放下手头所有工作,启动一套完整的“地下室取书”流程。
- 存在位为 0页表项中 Present 位为 0 表示虚拟页未驻留内存,CPU 无法完成地址翻译,必须唤起内核处理。
- 保护位违规即使页面在内存中,如果写操作遇到只读权限、用户态访问内核态页面,同样产生缺页异常,这类也叫“保护性故障”。
- 逻辑或关系以上任意一条成立,CPU 就暂停当前指令,跳转到内核的缺页处理程序。
缺页处理流程:地下仓库取书
缺页中断触发后,CPU 像图书馆的报警铃响了一样:当前正在执行的指令被挂起,控制权切换到内核的缺页处理程序。这一步叫“陷入内核”,系统要先保存现场(寄存器、程序计数器),查明是哪个虚拟页闯的祸。接着内核检查这一次缺页是否合法——如果进程访问了根本没分配的地址,就直接抛段错误(Segmentation Fault);如果合法,则进入取书流程。
取书流程分四步走。第一,寻找空闲页框:内存里哪儿有空书架,就把书放在那儿;如果没有空闲页框,就得按置换算法(如 LRU)把一个旧页先赶回仓库腾地方。第二,发起磁盘 I/O:根据缺页的虚拟地址换算出它在磁盘交换区(swap)或可执行文件中的位置,把数据读入这个页框。第三,更新页表:把“存在位”置 1,页框号填进页表项,同时让 TLB 里对应的旧条目失效——因为它现在可能指向旧数据了。第四,恢复用户进程,重新执行那条触发缺页的指令,这一次翻译必然命中。
同样是取书,情况却大不相同:有时书其实就在楼里的某个推车上,只要登记一下就能拿;有时却要坐电梯下地下室,在几千本书里翻找。缺页中断也分轻重缓急。
- 陷入内核CPU 捕获取页异常,保存用户态现场,切换到内核态缺页处理程序,相当于按下“紧急暂停”键。
- 分配页框从空闲页框链表中摘取一个物理页框;若没有空闲,则先执行页置换,把受害者页面写回磁盘。
- 磁盘读取将所需页面从磁盘的交换区读入页框,涉及寻道、旋转延迟和传输时间,是毫秒级开销。
- 更新页表与恢复填写页表项并刷新 TLB,最后恢复用户进程,重放那条指令。
缺页类型区分:楼内找书与地下室取书
如果老王查索引发现“此书在馆内,但位置未登记”——比如刚搬来还没上架,只需要花几秒钟重新登记位置,就能把书交给读者。这叫次缺页(Minor Fault):页面已经在物理内存中,只是页表项暂缺失或无效,内核只需重新建立映射、分配或修正页表项,不需要磁盘 I/O。对应到实际场景:不同进程共享同一个最近加载的页面、或者页面刚被读入还没来得及更新页表,都会发生次缺页。开销只有几十微秒。
主缺页(Major Fault)则是另一番光景:页面真的不在内存里,老王必须坐货运电梯下到地下仓库,在昏暗的灯下翻找,再把书搬上三楼。内核需要真正发起磁盘读,从交换区或文件系统把页面载入内存。一次主缺页的耗时在 5~10 毫秒量级——比内存访问慢十万倍,比一次次缺页慢几百倍。换句话说,一个进程如果频繁主缺页,它的执行速度会被磁盘拖到令人窒息。
老王是聪明人,他慢慢总结出了一套减少跑地下仓库次数的方法——与其把整本厚书搬上来,不如读者看到哪页搬哪页。
- 正常访问绝大多数访问不触发缺页,直接命中 TLB 或页表,耗时为一次内存访问 T\_mem。
- 次缺页页面在内存但映射缺失,只需更新页表,耗时 T\_minor 约几微秒。
- 主缺页需要磁盘 I/O,耗时 T\_major 以毫秒计,即使概率小也影响巨大。
调页优化策略:聪明管理员的小技巧
最简单的策略是一开始就把整个进程“需要的”页面全部装入内存,可一个程序往往用到不到十分之一的代码路径。操作系统用了更聪明的按需调页(Demand Paging):进程可以运行,但现在用不到的书先留在仓库,只有访问到的页面才调入内存。这样启动速度飞快,内存也省下了。代价是首次访问某个页面必定触发主缺页——这叫“冷启动缺页”,属于正常开销。
写时复制(Copy-on-Write, COW)是另一个绝活:进程 fork 出子进程时,老王不急着把父进程的全部页面复制一份,只把页表复制一份,所有页框标为只读,父子共享同一份物理页框。只有当其中一方要写入时,才触发一次保护性缺页,老王这时才真正复制一个页框给写的那方。这就像两位读者一起读同一本书,只要没人往上写笔记,就共用一本书;一旦有人掏出笔,管理员立刻复印一份。Linux 的 fork 之所以快,正是靠 COW 近乎零拷贝地创建子进程。
这些优化让缺页频率大幅下降,但并没有消灭缺页。如何知道一个系统的“缺页健康度”?老王抬头看了一眼大厅里的实时监控屏。
- 共享阶段fork 后父子进程指向同一组物理页框,页表项全部标为只读,拷贝成本为零。
- 首次写触发任何一方写共享页,触发保护性缺页,内核复制该页框并恢复双方的读写权限。
- 总节省相比全量复制,COW 只复制实际被写过的页面,剩余页面继续共享。
性能分析排查:图书馆效率仪表盘
图书馆大厅的监控屏上,实时滚动着“每小时仓库取书次数”。如果这个数字突然飙升,说明要么读者需求量暴涨,要么书架布局出了问题。操作系统的“取书次数”就是缺页率:每秒缺页次数,或每百万次内存访问的缺页数(Page Fault Rate)。当你用 vmstat 命令看到 si(swap in)和 so(swap out)两列数值不为 0 时,就说明系统正在频繁地进行主缺页换入换出——内存明显吃紧了。
最危险的现象叫抖动(Thrashing):当运行进程太多,每个进程分到的物理页框少到装不下它的工作集时,系统就像一家书架爆满、书刚放上去就被挤下来的图书馆——老王不得不疯狂地往返于地下室和楼层之间,磁盘 I/O 达到饱和,CPU 却闲得发慌,因为大家都在等缺页。此时吞吐量断崖式下跌。解决手段不外乎:减少并发进程数、增大内存、或者用更聪明的页置换算法(LRU、Clock 算法)保住工作集。
老王最终明白了:快表、页表、缺页中断,本质是一套“从快到慢再到适中”的多级缓存体系。TLB 是几纳秒的记忆,内存是百纳秒的书架,磁盘是毫秒级的仓库。每一次缺页,都是系统把成本高昂的磁盘访问,化解为一次可控的、有迹可循的搬运过程——而你读懂了它,就握住了系统性能的缰绳。
- 无缺页部分不发生缺页时,访问时间取决于 TLB 命中率 h,命中走快表,未命中才走内存。
- 缺页部分缺页率 p 乘以单次缺页处理时间 T\_page fault,占公式的主导项。
- 诊断阈值当缺页处理时间占比超过可接受范围(如 1% 的访问都在等磁盘),就应优先排查内存容量与置换策略。
AI 应用场景
Redis 缓存命中率优化:给内存当一次“图书管理员”
阶段:模型服务的在线推理阶段,特征读多写少场景
解决的问题:AI 推理服务依赖 Redis 存储特征数据,当 Redis 内存不足触发主缺页(swap)时,单次查询延迟从微秒暴涨到毫秒,导致在线服务超时。传统做法是盲目加内存;理解缺页中断后发现,缺页率才是核心指标,命中率不足时先看内存是否被换出,再决定扩容策略。
具体案例:某推荐系统在高峰时段出现 P99 延迟从 20ms 飙到 1.2s 的故障。用 vmstat 观察 si/so 持续非零,确定 Redis 发生主缺页换入换出;进一步用 info memory 确认内存碎片化严重。通过关闭透明大页、给 Redis 实例绑定固定 CPU、把热键数据预热进内存,缺页率下降 90%,P99 恢复稳定。
大模型推理显存优化:COW 思想在模型并行中的应用
阶段:大模型多进程推理的显存规划阶段
解决的问题:多个 GPU 进程加载同一份模型权重时,传统做法是一进程一份拷贝,显存瞬间爆炸。借鉴写时复制思想:让多个进程共享同一份只读权重页,只有梯度更新或 LoRA 微调时才复制被写页面。PyTorch 中可通过 torch.multiprocessing.set_sharing_strategy 结合 fork + 共享内存实现类似效果。
具体案例:一个 70B 模型权重约 140GB,在 8 卡 A100 上部署时,若每进程独立加载需要 1.1TB 显存。利用共享页 + COW 映射后,主副本只占 140GB,各进程按访问页按需映射,显存占用降至约 200GB,系统缺页中断次数下降 95%。
Python 演示
"""缺页中断与TLB模拟器:模拟进程的虚拟内存访问序列"""from collections import OrderedDict PAGE_SIZE = 4096FRAME_COUNT = 4TLB_CAPACITY = 2 class TLB: """LRU 快表,容量有限,满则淘汰最久未用的条目""" def __init__(self, capacity): self.capacity = capacity self.entries = OrderedDict() # vpn -> pfn def lookup(self, vpn): if vpn in self.entries: self.entries.move_to_end(vpn) return self.entries[vpn] return None def insert(self, vpn, pfn): self.entries[vpn] = pfn self.entries.move_to_end(vpn) if len(self.entries) > self.capacity: self.entries.popitem(last=False) class PageTable: def __init__(self): self.entries = {} # vpn -> (pfn, present) def lookup(self, vpn): return self.entries.get(vpn, (None, False)) def set(self, vpn, pfn, present=True): self.entries[vpn] = (pfn, present) def simulate(accesses): tlb = TLB(TLB_CAPACITY) pt = PageTable() frames = [] # FIFO 页框占用列表,存 vpn tlb_hits = 0 minor_faults = 0 major_faults = 0 for va in accesses: vpn = va // PAGE_SIZE pfn = tlb.lookup(vpn) if pfn is not None: tlb_hits += 1 continue pfn, present = pt.lookup(vpn) if not present: if len(frames) < FRAME_COUNT: pfn = len(frames) frames.append(vpn) minor_faults += 1 else: victim = frames.pop(0) pt.entries.pop(victim, None) frames.append(vpn) pfn = FRAME_COUNT - 1 major_faults += 1 pt.set(vpn, pfn) tlb.insert(vpn, pfn) total = len(accesses) print("TLB命中率: {:.2%}".format(tlb_hits / total)) print("次缺页: {} 次, 主缺页: {} 次".format(minor_faults, major_faults)) print("总缺页率: {:.2%}".format((minor_faults + major_faults) / total)) return tlb_hits, minor_faults, major_faults if __name__ == "__main__": # 程序访问序列:页码 1 2 3 4 1 2 5 1 2 3 4 5 6 2 3 4 5 6 7 1 page_seq = [1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5, 6, 2, 3, 4, 5, 6, 7, 1] va_seq = [p * PAGE_SIZE + (i * 17 % PAGE_SIZE) for i, p in enumerate(page_seq)] simulate(va_seq)
tlb.lookup(vpn)先查老王记忆:TLB 命中直接返回页框号,无需走页表,这是最快路径。self.entries.move_to_end(vpn)每次命中都把条目移到末尾,实现 LRU(最近最久未使用)淘汰策略。pt.lookup(vpn)TLB 未命中时才查页表,present=False表示页表项无效,进入缺页流程。if len(frames) < FRAME_COUNT还有空闲页框时直接分配,这是次缺页,开销极小。pt.entries.pop(victim, None)页框满时按 FIFO 淘汰一个旧页并清理其页表项,产生一次主缺页。tlb.insert(vpn, pfn)缺页处理完毕后把新映射写回 TLB,下次访问就能命中快表了。
常见误区
误区TLB 未命中和缺页中断是一回事,反正都是“没找到”,都需要去磁盘读数据。
正解两者差着十万八千里。TLB 缺失只是老王“记不住”,翻一下索引目录(页表)就找到了——页面还在内存里,开销是几十纳秒级别的内存访问。只有页表项的存在位为 0、页面根本不在内存时,才算缺页中断,需要毫秒级的磁盘 I/O。把 TLB 缺失误认为缺页,会导致对系统性能的误判:TLB 缺失率高说明缓存效率低,缺页率高则说明物理内存不足。
为何常见:因为 TLB 缺失和缺页中断都发生在“查找”过程中,初学者容易把“没查到”一概而论,忽略了其实 TLB 缺失后还有页表这一层兜底。
误区系统只要出现缺页中断,性能就一定崩了,所以缺页次数必须为零。
正解次缺页(页面已在内存、仅映射缺失)开销只有几微秒,按需调页导致的“冷启动缺页”更是完全正常的——程序首次访问某个页面必然缺页。真正危险的是主缺页率和抖动。合理的缺页策略是“容忍部分次缺页,打压主缺页”。比如 Redis 预热后仍然会有少量缺页,只要 si/so 为 0 且延迟稳定,系统就是健康的。
为何常见:很多人在监控面板里看到 pgfault 非零就紧张,没意识到页缺事件分为完全不同的两类,且现代 OS 按需调页的设计本身就依赖缺页机制工作。
误区缺页中断都差不多,无非是慢一点,优化时一起处理就行。
正解次缺页只涉及页表更新和数据结构的分配,约 1~10 微秒;主缺页需要寻道、旋转、传输整个磁盘块,约 5~20 毫秒,两者相差三个数量级。设计系统时,次缺页可以当作“可接受的日常开销”,而主缺页必须极力避免——它是数据库连接池、缓存服务延迟毛刺的元凶。优化方向也完全不同:次缺页靠减少页表分配次数、加大页大小;主缺页靠增加内存、调整置换算法。
为何常见:两者共用“缺页中断”这个名字,学习时容易混淆,实际操作时也很难一眼从监控里分辨,导致把精力花在了错误的地方。
误区TLB 命中率越高越好,那就把 TLB 做得超级大,把整个页表都装进去。
正解TLB 是 CPU 内部的硬件缓存,受限于面积、功耗和访问速度。TLB 过大时,查找延迟上升、功耗剧增,甚至慢于直接查页表。现代 CPU 普遍采用“多级 TLB”(L1 TLB 极小极快,L2 TLB 稍大稍慢)或“按需分配大小页”来平衡。真正提升 TLB 命中率的关键是局部性——把热数据聚拢、用大页(Huge Page)减少页表项数量,而不是盲目增大 TLB 容量。
为何常见:直觉上缓存越大越好,但忽略了硬件缓存的物理代价,也忽略了软件层面(局部性、页大小)对命中率更本质的影响。
面试题
Q1. TLB 的主要作用是什么?
- A.缓存最近用过的虚拟页号到物理页框号的映射← 正确答案
- B.存储进程的完整页表
- C.管理磁盘上的交换空间
- D.负责缺页中断的磁盘读取
答案:A。TLB 是 CPU 内部的翻译后备缓冲器,缓存最近用过的“虚拟页号 → 页框号”映射,加快地址翻译。进程的完整页表存放在内存中,磁盘 I/O 由内核处理,都不属于 TLB 的职责。就像老王的“记忆”只存热销书位置,而不是整本索引。
Q2. 次缺页(Minor Fault)和主缺页(Major Fault)的本质区别是?
- A.次缺页需要磁盘 I/O,主缺页不需要
- B.次缺页页面已在内存,主缺页必须从磁盘读入← 正确答案
- C.次缺页只发生在用户态,主缺页发生在内核态
- D.两者没有本质区别,只是名字不同
答案:B。次缺页是指页面已经在物理内存中,只是页表项缺失或无效,内核只需建立映射;主缺页则是页面不在内存,必须发起磁盘 I/O 读入。前者微秒级,后者毫秒级,两者差三个数量级。
Q3. CPU 访问一个虚拟地址时发现 TLB 缺失,接下来会发生什么?
- A.直接触发缺页中断
- B.立即抛出段错误终止进程
- C.遍历内存中的页表查找映射← 正确答案
- D.由硬件直接从磁盘读入数据
答案:C。TLB 缺失只代表“快表没记住”,接下来应去内存中查页表。若页表项有效,则获得页框号并可能将条目回填 TLB;只有页表项无效时才触发缺页中断。TLB 缺失是“老王记不住”,翻索引即可,不等于“书不在馆”。
Q4. 页表项中的存在位(Present Bit)为 0,表示什么?
- A.该页表项刚被淘汰,需要重新分配
- B.对应页不在物理内存中,访问会触发缺页中断← 正确答案
- C.对应页已被换出到磁盘但访问不需要
- D.该页已被多个进程共享
答案:B。存在位为 0 表示虚拟页未驻留物理内存——可能是从未被加载、也可能被换出到交换区。CPU 一旦见到存在位为 0,就暂停指令并触发缺页中断由内核处理。共享、淘汰等状态由页表项其他字段或页表的管理结构描述。
Q5. 以下哪些情况会触发缺页中断?
- A.访问的虚拟页存在位为 0← 正确答案
- B.对只读页面执行写操作(写时复制场景)← 正确答案
- C.普通 TLB 缺失
- D.用户态程序访问被限制的内核地址空间← 正确答案
答案:ABD。存在位为 0、保护位违规(包括 COW 写触发和用户态访问内核地址)都会引发缺页异常,需要内核介入。普通 TLB 缺失只需查内存中的页表,只要页表项有效就不会进入缺页流程,所以 C 不选。
Q6. 已知 TLB 命中率 h=0.98,快表访问时间 2ns,内存访问时间 100ns,则该系统的有效访问时间 EAT 约为多少?
- A.2ns
- B.4ns← 正确答案
- C.10ns
- D.100ns
答案:B。EAT = h×2 + (1-h)×(2+100) = 0.98×2 + 0.02×102 = 1.96 + 2.04 = 4ns。命中时只有 2ns 快表开销,而 2% 的缺失需要额外访问 100ns 内存。虽然缺失概率小,但对 EAT 的贡献与命中部分相当,这就是 TLB 优化如此关键的原因。
Q7. 某系统缺页率 p=0.001,内存访问时间 100ns,主缺页处理时间 8ms,则有效访问时间约为多少?
- A.约 100ns
- B.约 8.1μs← 正确答案
- C.约 0.1ms
- D.约 8ms
答案:B。EAT = (1-0.001)×100 + 0.001×8,000,000 = 99.9 + 8000 ≈ 8099.9ns ≈ 8.1μs。缺页概率仅千分之一,却把访问时间从 100ns 拉高到 8.1μs,放大约 80 倍。缺页这种“黑天鹅”事件对性能的影响一目了然。
Q8. 写时复制(COW)机制的特点包括哪些?
- A.fork 子进程时复制整个地址空间的页框
- B.父子进程先共享只读页框,首次写时副本才复制← 正确答案
- C.通过保护性缺页触发单页复制← 正确答案
- D.只复制被修改过的页面,未写页面继续共享← 正确答案
答案:BCD。COW 恰恰避免全量复制,fork 时只复制页表并把页框标为只读,双方共享。任一进程首次写入时触发保护性缺页,内核复制该页框并恢复权限。因此 A 错误,B、C、D 都正确刻画出 COW “共享 + 按需复制”的本质。
Q9. 进程访问一个从未被加载的页面,首次发生主缺页并从磁盘读入数据。这属于哪种调页策略的直接体现?
- A.预取调页
- B.按需调页← 正确答案
- C.全量常驻
- D.页着色
答案:B。按需调页(Demand Paging)的核心思想是“用到才加载”:页面首次被访问时触发主缺页,内核从磁盘载入。这也解释了为什么进程能瞬间启动——没有把所有代码页都搬到内存,而是边运行边搬。
Q10. 系统出现“抖动”(Thrashing)现象的根本原因是?
- A.TLB 容量太小导致命中率下降
- B.每个进程的驻留集小于其工作集,导致持续缺页换页← 正确答案
- C.页表项存在位全部为 0
- D.磁盘读取速度太慢
答案:B。抖动是“运行进程过多,平均到每个进程的页框数少于工作集需求”导致的。系统陷入“刚换入就被换出”的循环,磁盘饱和而 CPU 空闲。TLB 小只会增加地址翻译延迟,页表项全部无效是断电状态,磁盘慢是加剧因素而非根本原因。