内存分段与分页

内存分段与分页

💡 原文中文,约11100字,阅读约需27分钟。
📝

内容提要

文章梳理CPU与内存的通信机制及内存管理演进:先介绍地址、数据、控制三总线与高速缓存;再说明8086分段模型如何用段寄存器解决16位寄存器与20位地址总线不匹配;继而阐述32位保护模式下的分段分页共存、平坦模式、虚拟地址与页表;最后介绍64位长模式、线性地址、TLB及PAE扩展。

🔎

延伸解读

分段模型是硬件妥协的产物,而非设计初衷

文章指出,8086的分段模型本质上是为解决16位寄存器与20位地址总线不匹配而生的适配方案,并非为了内存安全或管理便利。段寄存器通过左移4位加偏移的方式扩展寻址范围,使16位CPU能访问1M内存。这一历史包袱因x86兼容性被长期保留,甚至影响了后续32位和64位架构的设计。理解这一点,有助于看清许多内存管理机制背后的真实动因。

平坦模式并未废除分段,只是将其“空转”

32位保护模式开启平坦模式后,操作系统将所有段描述符的基地址设为0、段长度设为4G,使段寄存器运算结果等于虚拟地址。文章强调,这层段地址运算依然存在,只是结果无效,属于兼容性保留。因此,所谓“纯分页”在x86上并不彻底,分段机制始终潜伏在地址转换链路中,直到64位长模式才将段基址和长度标记为无效位。

虚拟地址相同却映射不同物理地址,关键在缺页异常

两个进程使用相同的虚拟地址,MMU通过页表却能找到不同的物理地址,这看似违反函数映射的确定性。文章解释,页表初始为空,首次访问触发缺页异常,操作系统此时才将磁盘中的4KB页面加载到物理内存,并把实际物理地址写入页表。不同进程缺页时分配到的物理页不同,因此相同虚拟地址最终指向不同物理地址。这一过程由操作系统页表管理完成,应用程序无需感知。

PAE通过增加页表层级扩展寻址,而非改变分段

32位CPU地址总线为32根,最大寻址4G。文章提到,PAE技术将地址总线扩展到36根,使最大寻址达到64G,但实现方式并非依赖分段模型,而是在分页模型上增加一级页表:CR3寄存器不再直接指向页目录,而是指向页目录指针表。这与16位CPU通过分段扩展寻址的原理不同,说明扩展内存寻址可以基于分页机制独立完成,不必回退到分段方案。

❓

Q&A

CPU和内存之间通信需要哪几根总线?各自作用是什么?

需要地址总线、数据总线和控制总线。地址总线用于定位内存地址;数据总线用于CPU和内存之间双向传输数据;控制总线用于传递CPU对内存的控制指令,如读或写。

16位CPU只有16位寄存器,为什么能访问1MB内存?

因为8086的地址总线是20位,可寻址1MB空间。但16位寄存器只能直接表示64KB,所以Intel增加了段寄存器(cs、ds、ss、rs),通过段基地址左移4位加偏移量的方式(如cs*16+ip)生成20位物理地址,从而访问1MB内存。

32位保护模式下,分段和分页是如何共存的?

32位保护模式仍保留段寄存器以兼容,但操作系统会开启平坦模式,将所有段描述符的基地址设为0、段长度设为4G,使段寄存器运算实际不改变地址,从而主要使用分页模型。分页模型通过页表将虚拟地址转换为物理地址,实现内存管理。

两个进程的虚拟地址相同,为什么能映射到不同的物理地址?

因为每个进程有独立的页表,由CR3寄存器指向当前进程的页目录。当发生缺页异常时,操作系统会为不同进程分配不同的物理内存块,并将物理地址写入各自的页表。因此即使虚拟地址相同,通过不同页表转换得到的物理地址也不同。

线性地址和虚拟地址有什么区别?

在分页模型下,虚拟地址经过段寄存器处理后产生的地址称为线性地址。在32位平坦模式或64位长模式下,段基地址为0或无效,因此线性地址等于虚拟地址。但严格来说,程序里看到的是线性地址,经过分段模型后产生的才是虚拟地址,两者在分页模型下值相同,可视为别名。

什么是TLB?它和CPU缓存有什么关系?

TLB是CPU内部的高速缓存,专门用于缓存MMU页表运算的结果,以加速虚拟地址到物理地址的转换。它和CPU的L0-2级缓存类似,也分为指令地址缓存和数据地址缓存,同样需要处理脏数据标记和写回。

32位CPU如何通过PAE技术支持超过4GB的内存?

PAE技术将地址总线从32根扩展到36根,最大寻址范围从4GB扩展到64GB。它在分页模型基础上调整页表,将CR3寄存器指向页目录指针表,相当于增加一级页表,从而支持更大的物理地址空间。

🏷️

标签

➡️

继续阅读