起因:对下图内容的理解

Cache缺失(Cache Miss)由硬件完成
处理流程与模块: 当CPU访问数据时,会首先在高速缓存(Cache)中查找。如果发生Cache未命中(所需数据不在缓存中),处理器的硬件缓存控制器 会直接负责处理这一情况。这通常不会触发任何软件异常,而是由硬件自动执行以下步骤:
- ****内存层级访问:****硬件将请求发送到下一级存储(如L2/L3缓存或主存RAM),根据物理地址读取所需数据块。在访问过程中,CPU可能暂停相关指令的执行,相当于在流水线插入等待气泡(bubble),直到数据准备就绪。
- ****填充缓存:****一旦从下一级存储取回数据,硬件将把数据块加载到缓存中(可能需要选择一条缓存线进行替换,如果该缓存行已被修改则需写回内存)。同时更新缓存的标签(tag)等元数据。
- ****恢复执行:****缓存数据就绪后,CPU继续执行被暂停的指令,重新从缓存读取所需数据。对于程序来说,这一切都是透明的,除了该内存访问耗时略有增加,并不需要操作系统介入。
设计权衡与原因: Cache命中/缺失的检查和处理频繁且时间敏感,因此设计上由硬件完成 ,以最大化速度并最小化开销 。(1)性能考虑: 缓存访问非常频繁,如果每次缓存缺失都陷入操作系统,无疑会严重拖慢程序执行。事实上,缓存缺失通常仅导致处理器一次内存读操作的延迟,而不涉及复杂决策[3]。硬件可以在几个处理器时钟周期内检测并发起内存读取,使流水线短暂停顿而无需执行上下文切换。相比之下,软件介入(例如触发中断并调用OS处理)将耗费上千周期,无法满足高速缓存的性能要求。(2)透明性: 缓存设计旨在对软件透明。操作系统和应用无需知道数据在缓存或主存的位置,硬件自动维护这一层次。只要所访问的数据在主存中存在(没有发生更高层的缺页异常),处理器就能够自行完成缓存行的加载[3]。因此,Cache缺失不被视为需要软件处理的"故障",而只是一次正常的硬件内存访问延迟。正由于这些原因,所有主流架构(x86、ARM、MIPS等)都将缓存未命中的处理完全放在硬件中处理。
(补充:操作系统通常只在特殊情况下与缓存交互,例如进程切换时可能需要无效/清空缓存以避免不同进程间的数据干扰,或使用指令控制缓存的刷新和预取。但这些都是粗粒度的控制,不涉及每次缓存Miss的处理。)
缺页(Page Fault)由操作系统软件完成
情形简介: 虚拟存储系统中,进程使用的地址是虚拟地址,由硬件内存管理单元(MMU)通过页表转换为物理内存地址。如果某个虚拟页当前不在物理内存 (例如从未分配或已被换出到磁盘),那么硬件无法完成地址转换,此时会触发一次"缺页"(Page Fault)异常。不同架构对此有不同叫法,如x86架构产生页故障中断 (#PF),MIPS则通过TLB异常区分加载/存储缺页,但本质都是通知OS页面不在内存。关键在于,页故障处理需要操作系统介入 [4]。
处理流程: 缺页异常由操作系统的页面管理模块以软件方式处理,典型步骤如下:
- ****CPU触发异常并切换到内核态:****当MMU发现页表项标记页面无效,CPU停止当前指令的执行,将控制权转移给OS内核的页故障异常处理例程。硬件会提供必要的信息,例如发生异常的虚拟地址(如x86的CR2寄存器保存故障地址)和错误码(指示原因,如缺页或权限违规)。
- OS检查页面有效性: 操作系统首先确定该地址对进程是否有效。例如查询进程的内存映射结构(如Linux的VMA区域或页表)判断该虚拟地址是否属于合法的地址空间以及访问权限。如果属于非法访问(如越界地址或权限不符),OS会终止进程或发送信号(如Segmentation Fault信号)给进程处理,这是一种不可恢复的页面错误。
- 页面调度策略: 如果该地址确实是有效内存但只是未驻留内存(例如按需分页或被换出),OS需要为其调入物理页框(frame)。操作系统可能先在物理内存中分配一个空闲页框。如果内存已满,则根据页面替换算法(如LRU近似算法)选择一个"牺牲页"淘汰。若被淘汰页已被修改(脏页),则OS先将其内容写回硬盘的交换区(swap)或映射文件。
- 从外存加载页面: OS找到缺页对应的外存位置(例如二进制文件中的段地址,或之前换出的交换区位置),执行磁盘I/O将页面数据读入选定的物理页框中。这一步可能比较耗时,因为涉及磁盘访问。现代OS会将导致I/O等待的进程阻塞,调度其他进程运行,待I/O完成再唤醒之。
- 更新页表和TLB: 页面调入内存后,OS更新该进程的页表项,将虚拟页号映射到新的物理帧号,并将该页标记为有效。同时设置访问权限位等元数据。如果CPU使用硬件管理TLB(如x86),此时旧的TLB项已经无效,重新访问时硬件会自动从更新后的页表加载新的TLB项;在某些情况下OS也可能手动刷新或更新TLB (例如写特定寄存器或发TLB刷新指令)以确保新页表生效[5]。在软件管理TLB的架构上(如MIPS),OS还需使用特权指令将新的映射加载到TLB。
- ****恢复进程执行:****OS处理完页表更新后,将控制权返回给用户进程。CPU重新执行引发缺页的指令(在精确异常模型下,故障指令将重试访问)。由于页面现在已在内存且映射有效,本次访问即可成功完成,进程继续运行。整个过程对应用程序而言除了运行时间延长,并不需要修改程序逻辑。
设计考量与原因: 页面缺失涉及资源管理 和I/O延迟,必须由操作系统的软件来处理,主要原因如下:
- ****复杂决策与数据搬移:****与缓存Miss不同,缺页意味着所需数据根本不在内存,需要从磁盘等慢速介质取回。这涉及选择哪个页换出、调度磁盘读写,以及更新多种数据结构(页表、_swap_区管理等)。这些操作具有很强的系统全局性质和策略性,只有OS了解进程整体的内存使用情况和系统资源状态,才能做出合理决策。硬件实现这些策略既不现实也缺乏灵活性。举例来说,操作系统可以根据页面的访问历史选择最合适的淘汰页或决定预取策略,而硬件不具备这些高层策略判断能力。
- ****保护与权限检查:****操作系统负责内存访问控制。缺页异常提供了一个进入内核的机会,OS可以核对该访问是否合法。如果是非法访问,OS据此实施安全策略(如终止进程)。硬件本身无法判断访问意图是否符合程序逻辑或系统策略,只能按照页表位检查命中或不命中。因此需要软件介入来处理访问违规的情况。
- 频率与性能权衡: 相对于缓存命中率,缺页是相对低频 的事件(良好配置的系统中,缺页率应很低,否则性能会极差)。因此让OS处理缺页是可接受的------虽然一次页fault处理开销高(陷入内核加磁盘I/O可能上万甚至百万周期),但发生频率低,对整体性能影响有限[4]。同时,将这部分逻辑放到软件层面也简化了硬件设计,把复杂的内存管理任务交由OS完成。
总之,所有现代操作系统 (如Windows、Linux、macOS等)都将缺页作为一种同步异常,由内核中的缺页异常处理器完成实际处理[4]。硬件仅负责检测页表中的"不存在"位然后触发异常,把工作交给软件完成[5]。这种设计充分发挥了OS的管理能力,又保持了硬件的相对简单和高速处理常规内存访问的能力。
TLB缺失(TLB Miss)的硬件和软件处理方式
背景知识: TLB(快表,Translation Lookaside Buffer)是加速虚拟地址到物理地址转换的特殊缓存 ,存放最近使用的页表项。每当CPU进行内存访问,MMU会用虚拟页号查询TLB是否有对应的物理帧号。如果TLB命中则直接得到物理地址;若TLB未命中,则需要查找正式的页表获取地址映射[6]。这里就产生了两种不同的设计思路 :由硬件自动完成TLB重填 ,或由软件(OS)处理TLB缺失 。各大体系结构选择有所不同:例如x86、ARM等采用硬件管理TLB的方案,而MIPS、早期SPARC、Alpha等采用软件管理TLB的方案[7]。甚至有的架构(如PowerPC、Itanium)提供两种模式兼容。下面分别介绍两种方式的处理流程、涉及模块以及设计权衡。
硬件处理TLB缺失的流程(HW-managed TLB)
处理流程与模块: 在硬件管理TLB的体系结构中,内存管理单元(MMU) 会自动执行页表遍历操作 (也称页表走访,Page Table Walk),将缺失的映射加载到TLB中,整个过程对软件透明。以典型的x86架构为例,当TLB未命中时发生以下步骤:
- 硬件页表遍历: MMU从处理器的页表基址寄存器(如x86的CR3寄存器保存了当前进程页目录基地址)出发,按照预定义的页表结构查找目标虚拟页的映射。对于多级页表,MMU会逐级读取内存中的页目录、页表项:例如先用虚拟地址高位索引顶级页目录得到二级表地址,再索引二级页表找到物理帧号。[8][9]这一系列内存读取由硬件状态机执行,不需要软件插手。
- TLB填充: 如果页表中存在有效的物理帧号(PTE的有效位=1),表示所需页已经在内存中。此时MMU会将该页表项加载/写入TLB缓存,然后重新尝试访问内存[10]。由于TLB现已包含所需条目,这次访问将命中TLB,CPU即可顺利完成原指令的内存访问。整个过程对正在运行的程序而言没有中断,只是花费了额外的几十个时钟周期进行页表内存读操作[11][12]。
- 触发缺页异常(若需要): 如果在页表遍历过程中发现对应页表项不存在或标记为无效(即该虚拟页当前不在内存),那么硬件无法完成映射加载。这时MMU会停止遍历并产生一个页面异常 (page fault)中断,转交操作系统处理[13][12]。随后流程就与上述"缺页处理"相同,由OS加载页面并更新页表。操作系统处理完成后,重新执行导致缺页的指令,届时页表项已有效,硬件再次遍历页表即可填充TLB,然后访问内存成功完成。
设计特点与权衡: 硬件管理TLB的方法优势在于速度快、对软件透明 。TLB缺失时无需陷入内核,避免了异常处理的开销和流水线冲刷 。处理器仅仅暂停流水线等待MMU完成查表,随后即可继续执行,不用保存/恢复大量寄存器状态[12][14]。这对深度流水线和乱序执行的高性能CPU尤为重要------频繁的TLB异常会干扰流水线,硬件方案通过将TLB重填隐藏在硬件延迟中,使CPU流水线受到的冲击更小。因此,x86、ARMv7+、RISC-V等现代高性能处理器 大多采用硬件走访页表的TLB机制[15]。
然而,硬件方案的缺点 在于:(1)硬件复杂性提高: MMU需要内建状态机支持遍历页表,各级页表格式必须固化在硬件逻辑中。这增加了CPU设计复杂度,也限制了页表结构的灵活性------操作系统必须使用硬件规定的页表格式(如x86规定了多级页表的结构)。不同CPU微架构可以改变TLB实现细节,但页表布局对软件而言是固定的,不易定制。[16](2)内存开销: 为了让硬件高效查表,通常页表采用多级树状结构,可能在内存中占据较多空间。此外,OS需确保页表本身常驻内存,否则若页表的某部分被换出,硬件遍历时又会触发页表的缺页异常(这种情况下OS需先将对应页表页调入)。总体而言,硬件管理TLB倾向于以空间和复杂度换取时间,优先提升运行时性能。
软件处理TLB缺失的流程(SW-managed TLB)
****处理流程与模块:****在软件管理TLB的架构中,处理器将TLB未命中视为一种可以由软件解决的异常。以MIPS架构为代表,当TLB缺失发生时:
- 触发TLB异常: CPU检测到TLB查找失败后,会触发一条TLB缺失异常 (有时区分Load/Store TLB Miss等),切换到内核态执行预定的异常处理例程。硬件通常会将出错的虚拟地址保存到专用寄存器(例如MIPS的BadVaddr/EntryHi寄存器),以供软件查找映射用[17]。在进入异常处理时,CPU还会保存必要的状态(如异常返回地址) 以便处理完成后能恢复执行。
- ****软件查表寻址:****OS内核的TLB缺失处理例程(通常是高度优化的汇编代码)运行。它从专用寄存器读取产生缺失的虚拟地址或页号,根据该地址在操作系统维护的数据结构中查找对应的物理帧号。这里的"数据结构"可以是操作系统自定义的页表格式、哈希表或倒排页表等。以Linux on MIPS为例,内核维护着与进程虚拟内存区域对应的页表(但格式不受硬件约束),TLB异常处理代码会根据虚拟地址索引到相应页表项。如果该虚拟页已经在内存(页表项有效),则软件读出物理帧号;如果页表项本身不存在或无效,则说明这是一次真正的缺页,需跳转到通用的缺页异常处理代码,由OS按前述步骤调入页面。
- 更新TLB: 在找到有效的物理帧后,异常处理代码使用特权指令 将新的映射装入TLB。多数CPU提供插入TLB项的指令和寄存器(如MIPS有TLBWI/TLBWR等指令)。OS可能需要选择TLB中哪个项被替换掉 ------ 有的架构提供硬件辅助(如MIPS的TLB有随机替换寄存器Random帮助选择槽位),或者OS自行实现替换策略。相比硬件管理,这里替换策略完全由软件决定 ,因此OS可实现定制的TLB置换算法[17]。值得注意的是,为防止在TLB异常处理过程中再次发生新的TLB缺失,很多架构会将异常处理代码放在直映射的物理地址区域或使用固定映射(如MIPS的kseg0段),以确保处理代码本身不依赖TLB。
- ****恢复执行:****OS完成TLB更新后,通过异常返回指令恢复先前的CPU状态,让用户进程重新执行导致缺失的指令。由于所需映射已填充到TLB,这次地址转换将命中TLB,从而内存访问得以顺利进行,进程继续运行。整个软件填表过程虽然引入了一次内核陷入,但对应用是透明的(应用只感觉该指令执行稍慢,没有其他影响)。
设计特点与权衡: 软件管理TLB的主要优点在于灵活性高,硬件实现简单 。具体来说:
-
(1)页表结构灵活: 由于硬件不需要理解页表格式,操作系统可以按照自身需要设计页表和内存管理策略[18]。例如OS可选择单级、两级甚至倒排页表以及附加的统计信息等,而不受限于硬件规定格式。这在操作系统研究和不同OS移植中提供了方便。硬件只需提供基本的TLB存取指令和少量控制寄存器,复杂逻辑都在软件实现[19]。
-
(2)硬件开销低: 无需MMU执行自动查表,芯片设计更简单,节省晶体管和功耗。这与RISC设计理念一致------将复杂控制交由软件,以换取硬件简洁高效。当年MIPS等RISC架构选择软件填TLB,很大程度上是为了精简硬件,提高时钟频率。
-
****(3)策略可控:****OS掌握替换策略和时机,可结合操作系统层面的信息进行优化。例如可以避免替换某些关键TLB项(通过"wired"机制锁定TLB项),或在进程切换时保留部分跨进程通用的映射。另外,软件可以记录和利用更多统计数据(如缺页次数)来辅助内存管理决策,这些都是硬件难以提供的灵活性。
然而,其缺点 也显而易见:
-
(1)性能损耗: 每次TLB未命中都触发异常,进行内核态的软件查表,开销远高于硬件一步到位的查表。异常处理不仅耗费数百指令的执行时间,还会冲刷处理器流水线 ,在乱序执行处理器上尤为代价高昂[20][21]。虽然优秀的OS会尽量将TLB填充例程优化得很短并放在缓存友好的内存区域,但相比硬件方式依然慢一个数量级。特别在某些工作负载下(如大内存随机访问导致TLB命中率低),软件填表的性能瓶颈会显著影响整体系统吞吐。
-
(2)实现复杂度转移到软件: 操作系统的内存管理模块需要精心设计来处理TLB异常。开发者需编写架构相关的低级汇编代码处理异常、维护页表一致性(TLB与页表的同步)、以及考虑嵌套异常等边界情况。这增加了OS实现的复杂度。而硬件填表则免除了OS在这方面的大部分负担。
-
****(3)并发影响:****虽然处理TLB异常时CPU可以处理其他独立线程的指令(例如超线程技术可能允许另一个硬件线程继续),但在单CPU或单硬件线程上,TLB异常处理期间应用的执行被完全阻塞。硬件填表则等效于一次稍长的内存访问延迟,对CPU来说影响更局部。
实例对比: x86架构自386起采用硬件管理TLB,规定了多级页表格式,并由CPU自动完成TLB重填。当TLB缺失但页存在时,x86硬件行走页表填入TLB,对OS透明;仅在页不在内存时才触发缺页中断。[22][23] 相比之下,MIPS架构经典设计采用小容量全相联TLB,完全由软件管理。MIPS处理器将TLB miss作为异常跳转到0x8000_0000地址的内核例程,OS自行查一个软件维护的页表或内存区域获得物理地址,再用TLBWI指令写入TLB。MIPS硬件提供了Random寄存器辅助实现随机替换策略,但OS也可选择特定索引写入来实现自定义替换算法。
另外,IBM的老式VM/370主机采用硬件走访,DEC Alpha则采取折中方式:将TLB缺失处理封装在固件(PALcode)中,实现上类似软件处理但对操作系统透明[24]。Alpha的设计使得不同操作系统可以使用不同页表格式,只需提供相应PALcode即可,因为TLB格式和微码可以适配OS需求。这体现了一种固件管理TLB 的思路。本质上,无论硬件、软件还是固件,其目的都是在TLB缺失时找到正确的页表映射填入TLB [25][26]。
小结: TLB缺失处理机制的选择反映了体系结构在硬件复杂度与运行效率、以及OS灵活性之间的权衡[27][12]。硬件处理 适合追求极致运行性能的场景,典型于通用处理器;而软件处理 则简化硬件且给予OS更大控制权,曾流行于早期RISC处理器。随着技术发展和应用需求变化,现代主流CPU(包括x86-64、ARMv8、RISC-V等)大多采用硬件页表走访以减少地址转换开销[15]。但理解两种方式的差异,对于学习计算机体系结构和操作系统设计都有重要意义:它展现了硬件/软件分工在系统设计中的艺术------何时由硬件提速直捣快取,何时让软件统筹全局决策,是架构师需要深思的课题。正是这三种机制(缓存、TLB、虚存)的合理分工与协作,保障了现代计算机既有高速的内存访问,又具备灵活的内存管理和进程隔离能力。
参考资料:
- Cache缺失硬件处理: Cache未命中由处理器自行通过地址转换后访问更低层级存储完成,无需操作系统介入[3]。
- 缺页异常软件处理: 页故障总是由操作系统内核处理[4]。OS从外存将所需页面调入内存,更新页表后恢复程序执行[5]。
- TLB缺失处理方式: 部分架构(如x86)由硬件自动查页表填充TLB,未找到则引发页fault[11];部分(如MIPS)则触发异常由软件填充TLB,再无则缺页异常[26]。不同体系结构选择硬/软TLB管理各有权衡[17][12]。
[1] [2] [3] exception - Is cache miss a kind of interrupt/fault - Stack Overflow
https://stackoverflow.com/questions/16662834/is-cache-miss-a-kind-of-interrupt-fault
https://shd.mit.edu/2024/lectures/readings/6191-fall2023/L18.pdf
[5] [6] [12] [14] [17] [20] [21] [27] TLB 和cache 的设计及实现_tlb cache-CSDN博客
https://blog.csdn.net/weixin_42146650/article/details/142433819
[7] [8] [9] 常见架构TLB miss处理方法(转) - FREEH - 博客园
https://www.cnblogs.com/qiuheng/p/5685589.html
[10] [11] [13] [16] [19] [22] [23] [24] [25] [26] Translation lookaside buffer - Wikipedia
https://en.wikipedia.org/wiki/Translation_lookaside_buffer
[18] pasta.place
https://pasta.place/Informatik/Betriebssysteme/Tutorien/WS-16-17/Blatt_11/tutorial-11-solution.pdf