地址转译的相关问题(一)

虚拟地址描述符(VAD)

 

内存管理器使用一个按需换页(demand-pagin)算法计算何时将页面加载到内存中,要等到有一个线程引用一个地址并且招致一个页面错误时,从磁盘中获取该页面的数据

 

当一个线程通过VirtualAlloc提交一大块虚拟内存区域的时候,内存管理器可以立即构建起为访问这整块内存范围而需要的页表。但如果这范围中有一部分从来不会被访问到,为整个范围创建表是一种浪费。于此相反,内存管理器一直等到有一个线程引发了一个页面错误才创建一个页表,然后再为该页面创建一个页表。对于那些保留和/或提交了大量的内存但只是零星地访问这些内存地进程来说,提高性能。

 

采用延迟计算地算法后,即使分配大块内存也是快速地操作,当一个线程申请内存时,内存管理器必须用一段地址范围作为响应,以供线程使用。为了做到这一点,内存管理器维护了一组数据结构,跟踪和记录在进程地地址空间中哪些虚拟地址已经被保留了,哪些虚拟地址尚未被保留。这些数据结构称为虚拟地址描述符(VADVirtual address descriptor).

 

进程相关,描述该进程地址空间的状态,这些VAD被组织为一颗自平衡的二叉树,以便使查找过程非常高效-----AVL树算法:

 

当一个进程保留地址空间后者映射一个内存区的视图时,内存管理器创建一个VAD来存储此次内存请求所提供的任何信息,保留的地址的范围,该范围是共享的还是私有的、子进程是否可以继承此段范围的内容,以及应用在此段范围内的页面上的保护属性

 

当一个线程第一次访问一个地址,找到负责此地址的VAD,并利用找到的信息填充该PTE,如果该地址落在VAD所覆盖的地址范围以外,或者在一个已保留但尚未提交的地址范围之中,内存管理器知道该线程在使用此内存以前还没有申请该内存,产生一个访问违例。


MMVAD 结构中包含控制区域成员,而控制区域中包含了对应的内存区对象

typedef struct _MMVAD                   // 10 elements, 0x50 bytes (sizeof)
          {
            …
     struct _MMVAD* LeftChild;
     struct _MMVAD* RightChild;
     UINT64       StartingVpn;
     UINT64       EndingVpn;
             …
    struct _CONTROL_AREA* ControlArea;
    struct _MMPTE* FirstPrototypePte;
    struct _MMPTE* LastContiguousPte;
            …
          }MMVAD, *PMMVAD;

 

FirstPrototypePte指向一个原型PTE,当内存区对象被映射到一个进程的时候,FirstPrototype域指向所映射的视图在该内存区对象的原型PTE 阵列中的第一个PTE,LastContiguousPte指向与所映射的视图所对应的最后一个原型PTE

当内存区对象被映射到一个进程中的时候,内存管理器创建一个VAD对象,并初始化这两个PTE的指针域。对于一个VAD地址范围中的页面,当第一次被访问的时候,内存管理器可能需要为该页面构造一个有效的PTE,正是利用VAD中的信息来做到这一点

 

页面文件

页面文件用于存储那些已经被修改过的,虽然仍然在使用但不得不写到磁盘上的页面(通过已修改页面写出到磁盘的操作。当页面最初被提交的时候,页面文件的空间被保留了,但是,一直到这些页面被写出到磁盘上,它们在页面文件中的位置才真正确定下来。

 

内存管理器在全局基础上,记录了私有提交内存的使用量,其术语称为总提交量(commitment),而在每个进程的基础上,称为页面文件配额(page file quota).。一旦全局的提交量达到限制值(物理内存和页面文件已经满了)时,再申请虚拟内存将会失败,直到有进程释放已提交的内存为止(例如,当一个进程退出)。

 

系统引导的时候,会话管理器进程通过检查注册表值….\Session Manager\MemoryManagement\PagingFiles读入要打开的页面文件的列表,这是一个多字符串注册表值,包含了每个页面文件的名称、最小尺寸值和最大尺寸值。Windows最多支持16个页面文件,

普通 X86每个页面文件最多4096MB

X64 运行PAE内核的系统上,每个页面文件可以多达16TB

IA-64 系统上,每个页面文件可以是32TB


一旦页面文件被打开,系统运行过程中它不能被删除,因为System进程针对每个页面文件维护了一个打开的句柄,页面文件总是被打开的。

 

因为页面文件包含了进程虚拟内存和内核虚拟内存的一部分内容,为了安全起见,系统可以被配置成,当系统停机的时候清除掉页面文件的内容:HKLM\SYSTEM\CurrentControlSet\Control\SessionManager\Memory Management\ClearPageFileAtShutDown1.

 

为了加入一个新的页面文件,控制面板用Ntdll.dll中定义的NtCreatePaginFile系统服务。页面文件总是被创建成非压缩的文件,即使它们所在的目录是压缩的。为了避免新的页面文件被删除,该文件的一个句柄被复制到System进程中,因而,当创建此新页面的进程关闭了指向该文件的句柄时,另一个进程仍然可以打开此页面文件


系统内存池

所谓内存池,也就是一段地址空间

非换页池:“可保证总是驻留在物理内存中”的虚拟地址范围组成。

换页池:系统空间中的一段虚拟地址区域,可以被换入和换出系统。

单处理器系统有三个换页池,多处理器有五个。拥有多个换页池,可降低系统代码在并发调用池例程时的阻塞频率。非换页池和换页池都根据系统中物理内存的数量,从一个初始的大小开始,在有必要的时候再增大,一直达到一个系统在引导时计算好的最大值。

 

虚拟地址空间的布局结构

http://www.cnblogs.com/lanrenxinxin/p/5064671.html

 

地址转译

http://www.cnblogs.com/lanrenxinxin/p/4735027.html

上述博客介绍了通常的地址转译过程。




页目录的自映射

我们都知道,虚拟内存地址到物理地址的转译需要通过页表和页目录,通过上面我们也看到了,一个x86 虚拟地址的转译需要首先从页目录找到对应的页目录项,页目录项指向某个页表,然后从页表中取某个页表项,页表项指向了某个页面,再指定页面偏移之后就可以访问页面任意位置的内存了。

我们都指导,页目录的虚拟地址在x86的所有进程中都是一样的,即:0xC0300000,页目录的页目录项大小为4字节,共1024 项,即页目录整个的大小为4KB。另外,我们已经知道,CR3寄存器的值就是存储页目录页面的物理地址,然后又有页面内偏移值,因此我们其实并不需要虚拟地址的转换就可以得到页目录项PDE

 

但是我们知道计算机中的内存访问都是按照虚拟地址访问的,那么:

通过虚拟地址访问页目录是一个怎样的过程?


页目录物理地址为:0x1b235000

页目录虚拟地址为:0xC0300000

如果将虚拟地址表示为2进制:

1100000000 1100000000XXXXXXXXXXXX

不同颜色分别表示页目录索引,页表索引,字节索引,因为页目录大小刚好4KB,刚好为一个页面,因此,找到页目录页面的前面20位不变,变化的仅仅是后面的12位,由于页目录项大小为四字节,所以其值就等于4*页目录索引,即后二位始终为0。

1100000000 300-->指向页面中第0xC00偏移


此项PTE 指向页目录本身,即0x1b235000

然后就是页表索引,同样是0x300->指向页目录本身,最后12位业内偏移用于页目录偏移,因此,虚拟地址转译成物理地址同样“只需要最后12位偏移也就是一个10位的索引值即可”

这样我们可以发现,通过两次索引就可以找到虚拟地址对应的物理页面地址,而其中的页目录的概念只是为了便于理解,其实页目录项和页表项的解释是同样的。


上面简单介绍了正常的地址转译过程以及一些内存相关的概念

下一篇文章将介绍访问出错时的情况(这才是理解机制的关键)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值