在虚拟内存中,页表是个映射表的概念, 即从进程能理解的线性地址(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
首先说明内核的保护模式和是模式,在计算机刚刚启动的时候处于实模式,在该模式下cpu产生20位的地址,然后计算机经过某种变换转换到保护模式。保护模式下cpu产生32位的地址,也就是说从实模式到保护模式,cpu的寻址空间扩大了。在计算的发展的初期,intel 8086是16位的cpu,它只能运行在实模式下。在该模式下其寄存器是16位的,但是为了可以寻址20位的地址空间,所以采用了内存的分段模式。
物理内存地址=段基址×16+偏移 这样可以寻址20位的地址空间。
关于现代计算机内存的分段机制,也是为了向下兼容的需要。单纯的向下兼容或许还不够有说服力,因为在现代cpu中产生的就是32的地址,而由分段机制产生的线性地址也是32位的。32位的地址完全可以访问4G内存的任何一个地方,看上去分段机制好像完全没有了作用,其实不然。在多线程,多任务的 *** 作系统中,一个地址能否被一个进程写入,能被什么优先级的进程访问,是否允许执行这些问题有出来了。而解决这些问题需要在地址上添加一些属性,也就是说其地址应该还是高于32位的。这时候有体现了分段机制的作用。
关于分页机制。由分页机制产生线性地址,加入没有分页,这个线性地址就是物理地址。而分页机制就是把线性地址装换成物理地址。关于其原因,一方面在进程产生子进程的时候,会复制内存页,而父子进程无论是代码数据还是产生的地址都是一样的,这样为创建进程提供了便利,可以不必考虑进程在内存中分布的情况而产生地址,至于父子进程的真实物理地址在哪里,那是mmu(内存控制单元)的问题。另一方面,由于进程不知道真实的物理地址子啊什么地方,也为 *** 作系统提高了安全性。
可以通过管道将结果与more或者less命令联系起来使用,如ls | more,其中|即为管道的意思。说明:
管道:使用管道意味着第一个命令的输出会作为第二个命令的输入,第二个命令的输出又会作为第三个命令的输入,依此类推。利用Linux所提供的管道符“|”将两个命令隔开,管道符左边命令的输出就会作为管道符右边命令的输入。
more:分页查看文件内容
less:分页可控制查看文件内容
more和less的区别是more不支持后退,less支持前后翻滚。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)