ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

多级页表的基础理解

多级页表的基础理解 目录前言为什么抛弃「一级页表」引出多级页表多级页表核心思想 —— 拆分大表按需分配为什么虚拟地址是 32 bit以前说的「虚拟页号」去哪里了二级页表内存开销实例演算页目录的大小是确定的吗x86‑64 四级页表多级页表通用模型多级页表完整复盘 关联 TLB、缺页异常小结前言前篇学习总结与虚拟内存概念基础理解-CSDN博客学习总结与虚拟内存进阶-CSDN博客为什么抛弃「一级页表」引出多级页表背景一级页表的现实困境虚拟内存里页是内存最小管理单位常见页面大小4KB。32 位系统完整虚拟地址空间大小4GB。表格参数数值虚拟总空间4GB页面大小4KB单页表项大小4Byte计算 总页表项数量 4GB ÷ 4KB 1 048 576 条 单进程一级页表占用内存 1048576 × 4B 4MB✅ 一级页表逻辑很简单虚拟地址直接索引整张页表一次内存访问拿到物理页号。❌ 致命缺陷每个进程都需要完整一张页表无论进程实际用不用某块虚拟内存整张 4MB 页表必须全部分配在物理内存。现实中绝大多数进程只会用到很小一部分虚拟地址绝大部分页表项全程空闲但依然白白占用物理 RAM。进程数量一多内存被页表本身大量吞噬开销不可接受。问题32 位下一级页表单个进程页表需要占用多少物理内存一级页表最大的缺点是什么如果系统同时运行 200 个进程全部使用一级页表粗略估算页表一共消耗多少物理内存1.4M2.耗内存3.800MB“单进程一级页表占用内存 1048576 × 4B 4MB”是怎么计算的批改✔ 4MB正确。32 位单个进程一级页表占用4MB物理内存。✔ 完整表述无论进程实际使用多少虚拟内存整张页表必须全部驻留在物理内存大量无用页表项白白消耗 RAM。✔ \(200 \times 4\mathrm{MB}800\mathrm{MB}\)估算正确。可以直观感受到进程一多页表本身就吃掉巨量内存这就是一级页表硬伤。计算拆解已知条件32 位完整虚拟地址空间4GB2^32 Byte页面大小4KB2^12 Byte每个页表项占4Byte求一共需要多少条页表项 页表项总数 总虚拟空间 ÷ 一页大小2^32/2^12​2^201048576全部页表项占用内存 总字节数 页表项数目 × 单个页表项大小(4B)2^20×4 B4194304 B单位换算4194304 B÷1024÷10244MB通俗理解4GB 空间按 4KB 切分一共切出 1048576 个页面每个页面要登记一条 4 字节记录全部记录合起来就是 4MB。多级页表核心思想 —— 拆分大表按需分配一级页表问题根源一次性把全部页表项都分配出来很多条目全程闲置。多级页表解决思路把一张巨大的一级页表拆成多层小表。表格概念说明高层表页目录不存物理页信息只保存下层子页表的地址体量很小进程常驻内存下层子页表真正存放页表项 (PTE)负责虚拟地址→物理页映射核心关键点惰性分配只有当程序真正用到某一块虚拟内存区间时操作系统才去分配对应的下层子页表。 没有访问过的虚拟区间对应的子页表根本不占用物理内存。32 位二级页表的地址切分逻辑 把 32 位虚拟地址切成三段页目录索引(10bit) | 子页表索引(10bit) | 页内偏移(12bit)使用高 10 位 → 查询页目录拿到子页表的物理地址使用中间 10 位 → 查询子页表拿到物理页号低 12 位页内偏移保持不变拼接物理页号得到最终物理地址⚠️ 代价 一次地址翻译需要两次访问物理内存。这就是硬件 TLB 快表诞生的根源用来避免反复读内存。问题多级页表是如何减少物理内存消耗的32 位二级页表虚拟地址分为哪三段每段多少比特如果没有 TLB二级页表完成一次地址转换总共要访问几次物理内存:1.把整个页表拆分为多个小表真正访问时才会分配物理内存2.页目录索引子页表索引页内偏移3.2次为什么虚拟地址是32bit还有之前讲的虚拟页号去哪了:批改你的答案✔ 正确核心就是拆分 惰性分配未使用区间的子页表不占用物理 RAM。✔ 正确比特位数依次10bit、10bit、12bit。✔ 正确无 TLB 时查页目录 1 次查子页表 1 次合计 2 次内存访问。为什么虚拟地址是 32 bit32 bit 来源于32 位 CPU 架构。CPU 地址总线宽度为 32 根理论可以寻址 \(2^{32}4\mathrm{GB}\) 的地址空间。所以整个虚拟地址就用 32 比特来表达。这是硬件架构设定。x86‑32 → 虚拟地址 32bitx86‑64 → 虚拟地址 64bit硬件实际只用 48bit以前说的「虚拟页号」去哪里了在一级页表时代虚拟地址 虚拟页号 页内偏移高 20 位 虚拟页号低 12 位 页内偏移。进入二级多级页表之后虚拟页号被切割撕碎了原先完整 20 位的虚拟页号不再作为一整块编号被拆成两部分高 10 位 →页目录索引中间 10 位 →子页表索引\(\boldsymbol{虚拟页号(20bit)页目录索引(10bit)\;\;子页表索引(10bit)}\)本质没变还是用这 20 位定位页面只是不再一次性拿去索引一张大页表先拿高 10 位找子表再拿后 10 位在子表里找条目。 页内偏移 12bit 完全不动和一级页表完全一致。举个直观对比一级页表[虚拟页号20bit][偏移12bit]二级页表[目录索引10bit][子表索引10bit][偏移12bit]虚拟页号概念依然有效只是被拆成两段分别用于两层查表。二级页表内存开销实例演算前面只讲原理本段用实例直观感受多级页表节省内存的效果。 环境32 位4KB 页面二级页表。进程只使用一小块虚拟内存仅仅使用0‑4KB 这一个虚拟页面其余全部虚拟地址完全不访问。表格对象数量说明页目录1 张每个进程永远仅有 1 张页目录常驻内存一张页目录 1024 项每项 4B总大小4KB子页表1 张只分配需要的那一张子页表其余 1023 张子页表完全不分配物理内存页表项 (PTE)1 条仅仅 1 条有效映射对应唯一正在使用的虚拟页面✅ 总开销页目录 (4KB) 1 张子页表 (4KB) 8KB对比一级页表同样场景下必须占用完整4MB。 差距极其悬殊8KB vs 4MB。关键认知页目录每个进程固定 1 张开销很小。子页表按需创建没用到的区间子页表直接不分配。只有当虚拟地址落在新的区间发生缺页异常操作系统才会分配新的子页表。⚠️ 边界情况 如果一个进程把全部 4GB 虚拟空间全部用完那二级页表总开销反而会略大于一级页表。 因为页目录本身也要占内存。但现实业务几乎不会出现这种极端场景绝大多数程序只会用很小一部分地址空间多级页表整体收益巨大。问题条件32 位二级页表进程仅使用 0‑4KB 一个虚拟页面。该进程需要分配几张页目录几张子页表此种场景下二级页表一共消耗多少物理内存一级页表又是多少在什么极端场景二级页表内存开销会超过一级页表:1.1张 1张2.8kb 4mb3.频繁多次使用虚拟页面页目录的大小是确定的吗:批改答案✔ 1 张页目录1 张子页表正确✔ 二级页表 8KB一级页表 4MB正确❌ 不准确正确进程把全部 4GB 整个虚拟地址空间全部都占用使用时。所有 1024 张子页表全部分配出来额外再加上页目录本身的 4KB总开销就会超过一级页表的 4MB。页目录的大小是确定的吗在 32 位二级页表架构下每个进程的页目录大小是固定不变的。页目录一共 1024 个目录项每一项 4 字节 \(1024 \times 4\mathrm{B}4\mathrm{KB}\)不管进程实际用多少虚拟内存页目录永远是4KB不会变大、不会缩小。它是进程与生俱来就要分配的进程创建即存在。区分开页目录大小固定每个进程 1 份固定 4KB。子页表数量不固定按需分配用多少分配多少0 张1024 张浮动。拓展小思考 x86‑64 四级页表最高层 PML4 页目录同样是固定大小不会随进程内存使用量改变。变化的都是下层各级子表。x86‑64 四级页表多级页表通用模型32 位二级页表只是一个特例。64 位地址变大需要更多层级x86‑64 采用四级页表。核心思想和二级页表完全一模一样把虚拟页号拆成多段索引高层目录固定大小下层子表惰性按需分配减少内存开销。x86‑64 虚拟地址有效 48bit拆分PML4索引(9bit) | PDPT索引(9bit) | PDT索引(9bit) | PT索引(9bit) | 页内偏移12bitPML4最高层页目录每个进程 1 张固定大小。PDPT、PDT中间层子目录。PT最底层子页表存放真正页表项 PTE。低 12bit 页内偏移全程不变。表格层级作用分配策略PML4顶层目录每个进程固定 1 张常驻内存PDPT / PDT中间目录按需分配PT 底层页表存放 PTE 映射项按需分配⚠️ 无 TLB 情况下一次地址转换需要访问4 次物理内存。 层级越多查表访问内存次数就越多TLB 的重要性进一步放大。为什么不无限增加层级 每多一层就要多一次内存访问地址翻译速度下降TLB 压力变大。层级是在「页表内存开销」和「地址转换速度」之间做权衡。问题x86‑64 架构有效虚拟地址是多少比特而不是完整 64bit四级页表无 TLB 时完成一次地址翻译要访问多少次物理内存能不能无限增加页表层级把页表内存压到更小为什么:1.48bit 硬件限制2.4次3.不能 频繁访问内存导致效率低:批改✔ 48bit由硬件限制正确。x86‑64 CPU 只使用虚拟地址低 48 位。✔ 4 次PML4、PDPT、PDT、PT 各访问一次物理内存正确。✔ 不能层级每增加一层地址转换就要多一次内存读取转换效率急剧下降。本质多级页表是内存开销 ↔ 访问速度之间的权衡不是层级越多越好。补充小知识点48bit 虚拟地址拆分为 4 份 9bit剩余 12bit 做页内偏移 \(999912 48\) 每一层的索引都是 9 比特对应每一张页表 / 目录固定 \(2^9512\) 个表项这是 x86‑64 硬件规定。多级页表完整复盘 关联 TLB、缺页异常把前面全部知识点串联打通完整链路。1. 核心逻辑回顾一级页表缺陷必须分配完整大表进程多的时候页表本身消耗大量物理内存。多级页表方案把原先完整的虚拟页号切割成多段索引高层目录固定大小下层子表惰性按需分配没有用到的虚拟区间子页表直接不占物理内存。表格架构层级无 TLB 查表内存访问次数x86‑32 二级页表2 层2 次x86‑64 四级页表4 层4 次2. TLB 快表的定位TLB 是 CPU 内部高速缓存缓存已经翻译好的「虚拟页号→物理页号」映射。TLB 命中直接拿到物理页号不需要走多级页表不需要访问内存速度极快。TLB 未命中 (TLB‑miss)CPU 才走完完整多级页表流程多次读取物理内存完成地址翻译。3. 和缺页异常的联动CPU 执行访存TLB 未命中走多级页表查询。查询页表项时发现该虚拟页面还没有映射物理页。触发缺页异常陷入操作系统内核。OS 分配物理页分配需要的下层子页表填写页表项返回用户态程序继续运行。子页表本身也是在缺页异常里面由操作系统分配出来的。进程刚创建的时候只有顶层页目录存在下层全部子表都不存在。4. 几条必记结论虚拟地址空间大小由 CPU 硬件决定和进程实际用多少内存无关。高层目录大小固定下层子页表数量动态变化惰性分配。多级页表以增加内存访问次数为代价节约物理内存TLB 用来抵消这个性能代价。只有 TLB 失效的时候多级页表的多层查表流程才会完整执行。问题TLB 命中的时候还需要去访问多级页表吗进程刚被创建出来哪些页表相关结构已经存在哪些还没有分配子页表一般是在什么事件发生的时候由操作系统分配出来:1.不会2.页目录索引已经存在 子页表索引与页内偏移没有3.缺页异常:批改✔ 不会。TLB 命中直接得到物理页号完全跳过多级页表的内存查表流程。⚠️表述修正进程刚创建只有顶层页目录PML4 / 页目录已经分配并存在所有下层子页表全部没有分配。“页目录索引、子页表索引” 是虚拟地址里的比特位是地址本身的组成不是内存里的表结构。✔ 缺页异常发生时操作系统分配需要的子页表正确。小结一级页表痛点每个进程必须分配完整大页表大量空闲条目白白消耗物理内存。多级思想把虚拟页号切割成多段索引高层目录固定大小常驻内存下层子页表惰性按需分配未使用区间不占用 RAM。代价TLB 不命中时每多一层就要多访问一次物理内存靠 TLB 高速缓存抵消性能损耗。硬件约束x86‑32二级页表虚拟地址 32bitx86‑64四级页表仅使用 48bit 有效虚拟地址生命周期进程创建仅有顶层目录子页表在缺页异常中动态分配。
返回列表