在虚拟内存中,页表是个映射表的概念, 即从进程能理解的线性地址(linear address)映射到存储器上的物理地址(phisical address).
很显然,这个页表是需要常驻内存的东西, 以应对频繁的查询映射需要(实际上,现代支持VM的处理器都有一个叫TLB的硬件级页表缓存部件,本文不讨论)。
1.1 为什么使用多级页表来完成映射
但是为什么要使用多级页表来完成映射呢?
用来将虚拟地址映射到物理地址的数据结构称为页表, 实现两个地址空间的关联最容易的方式是使用数组, 对虚拟地址空间中的每一页, 都分配一个数组项. 该数组指向与之关联的页帧, 但这会引发一个问题, 例如, IA-32体系结构使用4KB大小的页, 在虚拟地址空间为4GB的前提下, 则需要包含100万项的页表. 这个问题在64位体系结构下, 情况会更加糟糕. 而每个进程都需要自身的页表, 这回导致系统中大量的所有内存都用来保存页表.
设想一个典型的32位的X86系统,它的虚拟内存用户空间(user space)大小为3G, 并且典型的一个页表项(page table entry, pte)大小为4 bytes,每一个页(page)大小为4k bytes。那么这3G空间一共有(3G/4k=)786432个页面,每个页面需要一个pte来保存映射信息,这样一共需要786432个pte!
如何存储这些信息呢?一个直观的做法是用数组来存储,这样每个页能存储(4k/4=)1K个,这样一共需要(786432/1k=)768个连续的物理页面(phsical page)。而且,这只是一个进程,如果要存放所有N个进程,这个数目还要乘上N! 这是个巨大的数目,哪怕内存能提供这样数量的空间,要找到连续768个连续的物理页面在系统运行一段时间后碎片化的情况下,也是不现实的。
为减少页表的大小并容许忽略不需要的区域, 计算机体系结构的涉及会将虚拟地址分成多个部分. 同时虚拟地址空间的大部分们区域都没有使用, 因而页没有关联到页帧, 那么就可以使用功能相同但内存用量少的多的模型: 多级页表
但是新的问题来了, 到底采用几级页表合适呢?
1.2 32位系统中2级页表
从80386开始, intel处理器的分页单元是4KB的页, 32位的地址空间被分为3部分
单元
描述
页目录表Directory最高10位
页中间表Table中间10位
页内偏移最低12位
即页表被划分为页目录表Directory和页中间表Tabl两个部分
此种情况下, 线性地址的转换分为两步完成.
第一步, 基于两级转换表(页目录表和页中间表), 最终查找到地址所在的页帧
第二步, 基于偏移, 在所在的页帧中查找到对应偏移的物理地址
使用这种二级页表可以有效的减少每个进程页表所需的RAM的数量. 如果使用简单的一级页表, 那将需要高达220个页表, 假设每项4B, 则共需要占用220?4B=4MB的RAM来表示每个进程的页表. 当然我们并不需要映射所有的线性地址空间(32位机器上线性地址空间为4GB), 内核通常只为进程实际使用的那些虚拟内存区请求页表来减少内存使用量.
1.3 64位系统中的分页
正常来说, 对于32位的系统两级页表已经足够了, 但是对于64位系统的计算机, 这远远不够.
首先假设一个大小为4KB的标准页. 因为1KB覆盖210个地址的范围, 4KB覆盖212个地址, 所以offset字段需要12位.
这样线性地址空间就剩下64-12=52位分配给页中间表Table和页目录表Directory. 如果我们现在决定仅仅使用64位中的48位来寻址(这个限制其实已经足够了, 2^48=256TB, 即可达到256TB的寻址空间). 剩下的48-12=36位被分配给Table和Directory字段. 即使我们现在决定位两个字段各预留18位, 那么每个进程的页目录和页表都包含218个项, 即超过256000个项.
基于这个原因, 所有64位处理器的硬件分页系统都使用了额外的分页级别. 使用的级别取决于处理器的类型
平台名称
页大小
寻址所使用的位数
分页级别数
线性地址分级
alpha8KB43310 + 10 + 10 + 13
ia644KB3939 + 9 + 9 + 12
ppc644KB41310 + 10 + 9 + 12
sh644KB41310 + 10 + 9 + 12
x86_644KB4849 + 9 + 9 + 9 + 12
linux运行在保护模式下,并且在启动保护模式之前准备好了分页式内存管理的页表,在进入保护模式的同时一并开启了分页模式(同时置PE和PG位,即or eax,0x80000001)。需要注意的是不要把保护模式和分页模式混淆,与实模式相对的是保护模式,与分页式内存管理相对的是分段式内存管理;当然,也有两者结合的段页式。
你这个问题太宽泛了,不同的 *** 作系统有不同的管理方式,采用不同的数据结构。但是大体说来,可以分为页式、段式和段页式三种。现在比较流行的 *** 作系统,如windows和linux,主要采用的是以分页式为主的内存管理方式,段式的功能基本不太用到了。
当然这里面涉及到很多技术细节,就不是在这里能讲清楚的了,推荐你看相关的书籍,比如<windows internals><深入理解linux内核>等
希望对你有所帮助!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)