Windows内存之内存分页

前面说道操作系统的每个进程都拥有自己的虚拟地址空间,对于这个32位操作系统,虚拟内存空间大小为4G。现代操作系统都使用分页来管理内存,把4G分成每一页为2^12 = 4K大小的页,一共有1M个的页(虚拟页VP,VirtualPage)。每一个虚拟页映射到物理内存空间的一个页——物理内存地址空间也划分4K大小的页(物理页PP,PhysicalPage)。这个映射关系的数据结构称为页表。当进程的虚拟页找不到可用的物理页的时候操作系统会执行一个页错误机制,进行物理页和磁盘页的置换。下面进行详细介绍。

目录

1.页表

1)一级页表

2)二级页表

页表自映射

2.页错误Page fault

DP和PP的置换过程


1.页表

页表是将虚拟地址转换成物理地址所需要的映射表,需要存储在物理内存中,可供操作系统和MMU进行查询和更新。

页表设计可以分成一级页表,二级页表和多级页表。这里介绍一级页表和二级页表。涉及到虚拟地址的划分。

1)一级页表

在使用一级页表的映射表中:32位虚拟内存地址=20位页表索引+12位页内偏移

因为每一页的大小是4K=2^12,所以页内偏移的位数需要12位。那么前20位就是页索引部分。

页映射表的大小也就是2^20 = 1M大小的表(List),即表元素的个数为1M。我们用4个字节来存储每个元素(即用来存储映射的物理页号,虽然不需要用到32位地址。因为物理页的数量不会有4GB这么多),存储这个映射表就需要的是4M的内存(即每次创建一个进程,都需要先在物理内存中占用一个4M的映射表)。

2)二级页表

其实对于一个普通的程序,虚拟内存空间中的很大一部分虚拟页都是未使用的,所以给这些虚拟内存页分配存储空间(映射到物理空间页的项)是浪费的。所以给32位虚拟地址进一步划分,采用二级页表的方式:

32位虚拟内存地址=10位页目录索引+10位页表索引+12位页内偏移

即在一级页表中,把20位的页表索引再次切分,为10位页目录索引和10位的页表索引。即一个虚拟空间先对应一个2^10 = 1024个元素的页目录,每个页目录再对应一个2^10=1024个元素的页表。每个页表的大小即为一个虚拟页大小为4K。即总共4GB的虚拟内存。

  • 页目录

每个虚拟地址空间对应一个页目录,共有2^10=1024个页目录项((PDE = PageDirectoryEntry)),即1K大小的表。每个页目录项为4个字节,用来指向一个页表,所以这个页目录一共需要4K的内存。

  • 页表

每个页表包含2^10 = 1024个页表项(PTE = PageTableEntry),每个页表项也是4个字节,其中前20位真正的指向一个物理地址(物理页,这里假设是最大支持的物理内存是4GB=4K*1M 1M = 2^20),后面12位用表示各种标志信息。

基于这种虚拟地址的构成,cpu先根据虚拟地址的最高10位,定位到一个页目录项,再根据中间10位,定位到该页目录项指向的页表的页表项,由此就得到了映射的物理页的地址,最后再对应加上页内偏移就是最终的物理地址。

  • 占用内存

对于维护一个满的虚拟地址空间。需要4M(页表)+4K(页目录)大小的物理内存,比线性表多了4K。但是在很多情况下,虚拟空间的使用只占很少一部分,这样只创建需要4K的页目录,以及所需要的页表即可,每个页表是4K大小。这样极大的节省的每个进程所必须的映射表的内存开销。

  • TLB

二级页表付出的代价就是在解析地址时,需要进行两次查表操作。为了避免多级页表解析过程中多次查表导致的性能问题,cpu专门有个TLB(Translation Lookaside Buffer, 地址转译快查映射信息)记录了最近使用过的页面的内存映射信息,可以快速查到虚拟地址对应的物理地址。所以在进行一次地址翻译的时候,先查找TLB中有没有对应的信息,没有再进行二次查表,然后把信息记录到TLB。因为计算机程序的内存访问具有一定局部性,cpu维护一个小的TLB,就能使程序的运行得到显著的性能提升。

  • CR3

每一个进程都一个CR3寄存器。CR3寄存器包含了该进程虚拟空间对应的页目录的物理地址。当cpu切换CR3的时候,也就意味着从一个虚拟地址空间切换到了另一个虚拟地址空间。此时会将TLB中的映射项失效。(除非映射项的PTE的全局标志位,低12位的第8位是一个全局项,这还会保留这个映射项)

页表自映射

页面自映射参考文章:

https://blog.csdn.net/u010513059/article/details/80311248 题倒是看懂了。

https://blog.csdn.net/panaimin/article/details/5918359 没怎么理解 页目录地址0xc0300000和这里的0x300项绝不是偶然的 。下面的评论可以仔细看看


2.页错误Page fault

当进程访问已映射在虚拟内存空间,但当前并未被加载在物理内存的一个分页时,由MMU所发出的中断。发生页错误可能是有两种情况:

1.相关的页已经被加载进内存,但是没有在页表中有映射信息的情况。操作系统只需要在增加映射信息即可。发生这种情况的可能性之一,是一块物理内存被两个或多个程序共享,操作系统已经为其中的一个装载并映射了相应的页,但是没有为另一个程序映射。

2.相关的页在页缺失发生时未被加载进内存的情况。这时操作系统需要

  1. 寻找到一个空闲的页。或者把另外一个使用中的页写到磁盘上(如果其在最后一次写入后发生了变化的话),取消之前的映射关系。
  2. 将数据读入1中被选定的页
  3. 更新映射表

DP和PP的置换过程

程序运行时并不是所有的页(VP)都在物理内存上(PP),有一些页会保存在磁盘上(DP)。当需要用到保存在硬盘上的这些页时,这时会发生一个页错误中断。接着操作系统会在物理地址空间中为这些页分配物理内存页(PP),将相关的分页从硬盘上的虚拟文件中调入物理内存中。然后建立虚拟地址空间中的页(VP)和刚分配的物理内存页(PP)间的映射。

比如程序A的虚拟空间被分成了7个页为VP0-VP7,程序运行时的某一时刻VP0 VP1 VP7映射到了物理内存PP0,PP2和PP3中,而VP2,VP3存在硬盘中,VP4,VP5,VP7未被访问或使用到,属于未使用的状态。当进程需要用到VP2和VP3时,硬件会捕捉到这个页错误。捕捉到页错误以后,操作系统会接管进程,负责将VP2和VP3,从硬盘中读出来,装入可用的物理内存中,然后将VP2和VP3 对应转入的物理内存页建立映射关系(更新页表)。然后操作系统控制权交还给进程,进程再次使用VP2和VP3的时候,就能访问到对应物理内存页了。

发布了104 篇原创文章 · 获赞 44 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/u012138730/article/details/90271193