内存分页

转自百度文库:http://wenku.baidu.com/view/61cf20640b1c59eef8c7b4ef.html 



1. Linear Space & Physical Space 


在硬件工程和普通用看来,内存就是插在或固化在主板上的内存条,它有一定的容量——比如64 MB。但在用程序眼中,并不度关心插在主板上的内存容量,而是他可以使用的内存空——可以开一个需要占用1 GB内存的程序,并其在OS平台上运行,哪怕台运行主机上只有128 MB的物理内存条。而OS者而言,是介于二者之,他既需要知道物理内存的细节,也需要提供一套机制,为应用程序提供另一个内存空 内存空的大小可以和实际的物理内存大小之没有任何关系。

将主板上的物理内存条所提供的内存空义为物理内存空;将用程序看到的内存空义为线性空。物理内存空大小在不同的主机上可以是不一 的,随着主板上所插的物理内存条的容量不同而不同;但为应用程序提供的线性空却是固定的,不会随物理内存的化而化,这样才能保证应用程序的可移植 性。尽管物理内存的大小可以影响用程序运行的性能,并且很多情况下物理内存的大小有一个最低要求,但些因素只是一个OS可以正常的运行。

线性空的大小在32-bit平台上4 GB的固定大小,于每个程都是这样(一个用可以是多程的,在OS眼中,是以为单位的)。也就是说线性空不是程共享的,而是程隔离的,每 程都有相同大小的4 GB线性空。一个于某一个内存地址的访问,与其它于同一内存地址的访问绝不冲突。比如,一个线性空地址1234ABCDh可以 出整数8,而另外一个线性空地址1234ABCDh可以出整数20取决于程自身的逻辑

在任意一个刻,在一个CPU上只有一个程在运行。所以于此CPU,在刻,整个系只存在一个线性空线性空是面向此程的。当 生切候,线性空也随着切。所以结论就是每个程都有自己的线性空,只有此程运行的候,其线性空才被运行它的CPU所知。在其它 刻,其线性空间对CPU,是不可知的。所以尽管每个程都可以有4 GB线性空,但在CPU眼中,只有一个线性空的存在。线性空化,随着程切化。

尽管线性空的大小和物理内存的大小之没有任何关系,但使用线性空用程序最终还是要运行在物理内存中。用所出的任何线性地址最 物理地址,才能真正的访问物理内存。所以,线性内存空被映射到物理内存空中,个映射关系需要通使用硬件体系构所定的数据构来建立。我 不妨先称其映射表。一个映射表的内容就是某个线性内存空和物理内存空的映射关系。OS Kernel一旦告某个CPU一个映射表的位置,那么CPU需要去访问一个线性空地址,就根这张映射表的内容,将线性空地址物理 地址,并将此物理地址送到地址线竟地址线只知道物理地址。

所以,我很容易得出一个结论,如果我们给出不同的映射表,那么CPU将某一线性空地址化的物理地址也会不同。所以我们为每一个程都建立一映射 表,将每个程的线性空根据自己的需要映射到物理空上。既然某一刻在某一CPU上只能有一个用在运行,那么当任务发生切候,将映射表也更 的映射表就可以实现每个程都有自己的线性空而互不影响。所以,在任意刻,于一个CPU,也只需要有一映射表,以实现当前程的线性空 到物理空化。 

--------------------------------------------------------------------------------

2. OS Kernel Space& Process Space 


由于OS Kernel在任意刻都必存在于内存中,而程却可以切,所以在任意刻,内存中都存在两部分,OS Kernel和用户进程。而在任意刻,于一个CPU只存在一个线性空,所以线性空被分成两部分,一部分供OS Kernel使用,另一部分供用户进程使用。既然OS Kernel在任何候都占用线性空中的一部分,那么于所有程的线性空而言,它们为OS Kernel所留出的线性空可以是完全相同的,也就是,它各自的映射表中,也分两部分,一部分是程私有映射部分,OS Kernel映射部分的内容完全相同。

个意上来,我可以认为于所有的程而言,它共享OS Kernel所占用的线性空部分,而每个程又各自有自己私有的线性空部分。假如,我将任意一个4 GB线性空分割1 GBOSKernel部分和3 GB程空部分,那么所有程的4 GB线性空1 GBOS Kernel是共享的,而剩余的3 GB程空部分是各个程私有的。Linux就是么做的,而WindowsNTOS Kernel程各使用2 GB线性空 

--------------------------------------------------------------------------------

3. Segment Mapping & Page Mapping 


所有的线性空的内容只有被放置到物理内存中才能被真正的运行和操作。所以,尽管OS Kernel程都被放在线性空中,但它被放置到物理内存中。所以OS Kernel和所有的程都最共享物理内存。在现阶段,物理内存没有线性空那么大——线性空4 GB,而物理内存空往往只有几百兆,甚至更小。另外即使物理内存有4 GB,但由于每个程都可以有3 GB线性空(假如程私有线性空3 GB),如果把所有程的线性空内容都放在物理内存中,明是不现实的。所以OS Kernel将某些暂时用不到的数据或代放在物理内存之外,将有限的内存提供当前最需要的程。另外,由于OSKernel在任何候都有可能运行,所以OS Kernel最好被永放在物理内存中。我们仅仅程数据出。

线性空到物理空的映射需要映射表,映射表的内容是将某段线性空映射到相同大小的物理内存空上。从理上,我可以使用两种映射方法:变长映射, 和定映射。变长映射指的是根据不同的需要,将一个一个变长段映射到物理内存上,其格式可以如下(线性空段起始地址,物理空段起始地址,段)。假 如一个程有3个段:10M的数据段,5M的代段,和8K的堆段,那么就可以在映射表中建立3内容,每一项针对一个段。看起来没有问题。但假如 在我实际的内存只有32M,其中10M被内核占用,留给进程的物理空只有22M,那么此程在运行,就占据了10M+5M+8K的内存空。随后 生切换时,假如另一个程和其有相同的内存要求,那么剩余的22M-(10M+5M+8K)就不用了,这时只能将原程的某些段出,并且 是整段的出。就意味着我出一个10M的数据段,而出的成本很高,因10M的内容拷到磁上,磁I/O是很慢的。

所以,使用变长的段映射的果就是一个段要么被全部入,要么被全部出。但在现实中,一个程序中并非所有的代和数据都能访问,往往被访问 的只占全部代数据的一部分,甚至是一小部分。所以更有效的策略是我最好只出那些并不常使用的部分,而保留那些常被使用的部分。而不是整个段的 出。这样可以避免大的慢速磁操作。

就是定映射策略,我将内存空分割一个个定长块,每个定长块被称一个。映射表的基本格式(物理空间页起始地址),由于是定的,所以不需 要指出它的度,另外,我不需要在映射表中指定线性地址,我可以将线性地址作索引,到映射表中索出相的物理地址。当使用页时,其策略:当 候,我只将那些不活的,也就是不常使用的页换出,而保留那些活。在入的候,只有被访问才被入,没有被访问将永 会被入到物理内存。就是Demand Page)算法的核心思想。

就引出一个大小的问题:首先我不可能以字节为单位,这样映射表的大小和线性空大小相同——假如整个线性空都被映射的——不可能将全部线 用作存放个映射表。由此,我也可以得知,越小,映射表的容量越大。而我不能映射表占用太多的空间(页越小需要的映射表空间越大,就如蛋糕切的越小,就需要切的刀数也越多,能分到的人越也越多)。但如果太大着和不定段映射 问题,每次出一个,都需要大量的磁操作。另外,由于一个程分配内存的最小位是,假如我大小4 MB,那么即使一个程只需要使用4 KB的内存,也不得不占用整个4 MB是一种很大的浪。所以我在两者之间进行折衷,一般平台所定的大小1 KB8 KBIA-32定的大小4 KB。(IA-32也支持4 MB,你可以根据你的OS的用途选择,一般都是使用4 KB)。 

--------------------------------------------------------------------------------

4. Page Table 


假如使用4 KB,那么4 GB线性空需要1,048,576体,每个表占用4个字需要4,194,304个字仅仅页表就占用4 MB是一个很大的需求。但如果确确实实一个程需要使用全部线性空,那么4 MB表空投入也是必要的。

但在现实中,很少有那个程序需要使用么大空,一般的程序往往很小,从几KB到几MB,再使用么大的表就粹是一种浪。那我们该怎么

一种策略是建立变长页——只建立所需度的表。但种策略来很大的限制,并且仍然会造成比大的空。由于表机制是使用线性地址作 引,到表中索。那么如果我OS Kernel使用C0000000h-FFFFFFFFh,也就是3GB-4 GB线性空,那么表的3 MB以上部分肯定被使用,那么是不得不占用大于3 MB的空,即使仅仅使用1 KB线性空。除非我OS Kernel放在0h-3FFFFFFFh,也就是第一个1 GB线性空。即使是这样,我表也必至少占用1 MB的空,尽管实际上我的内核可能只有4 MB,只需要1024个表,也就是4 KB——为进程私有的线性空是从40000000h开始的。另外,于共享而言,它一般被放在物理内存的某个位置,同映射到某个线性空 位置,个映射关系所有的程都是一致的。每个程都将所需共享的映射关系放在自己的表中。户进程留出足的空,共享一般被映射到 高的线性空,比如2 GB的位置。那么至少需要2 MB以上的空之,变长页表无法真正解决表空问题

另外一种策略是使用多级页表。我4 KB的二级页例来明多级页表的原理。

级页表的第一为页(Page Directory),第二为页(Page Table)

如果使用一级页表,则对4 KB的来,其起始地址都是以4 KB=2^12对齐的,所以一个线性地址的低12-bit用来做址。高20-bit被用来做表索引。而如果使用2级页表,将其高20-bit 两部分,比如我210-bit,高位的10-bit用来做PageDirectory的索引,用于定位Page Table;低位10-bit用来做PageTable的索引,用于定位Page;最低的12-bit用于定位Offset。所以通3部分的合,一个32-bit线性地址就最终转一个32-bit的物理地址。


在整个2级页表架构中,只存在一个Page Directory,由于索引是10-bit,所以中有2^10=1024Directory Entry)。一个Directory Entry4个字,所以大小1024*4 = 4 KB,恰好被放在一个中。每一个Directory Entry指向一个表,所以最多有1024Page Table,但并非所有Page Table都需要存在。每一个Page Table的索引也是10-bit,所以一个Page Table中有2^10=1024表表Page-TableEntry);一个Page-Table Entry4个字,所以一个Page Table大小1024*4 = 4 KB,也恰好被放在一个中。所以一个Directory Entry的高20-bit加上全0的低12-bit,就是其所指向的Page Table所在的起始地址。一个Page-Table Entry的高20-bit加上全0的低12-bit,就是其所指向的Page的起始地址。

这样,当我们给出一个32-bit线性地址,首先取出高10-bitPage Directory的索引,找到相Directory Entry,然后根据此Directory Entry的高20-bit找到相Page Table所在的Page,再根据线性地址的中10-bit索引,在此Page Table中找到相Page-Table Entry,然后根据此Page-Table Entry的高20-bit找到相Page,最后根据线性地址的低12-bitOffset,加上Page Base Address化成了32-bit的物理地址。

就是2级页表的线性地址到物理地址的映射机制。在2级页表中,PageDirectory占用4 KB2级页表的最小内存需求。Page Table根据实际的需要而建。假如OS Kernel被放在3 GB的位置,大小4 MB只需要建一个Page Table,然后将Page Directory的第768DirectoryEntry设为指向此Page Table所在的基地址。如果程自身占用4 MB,占用线性地址0-4MB只需要再建一个Page Table,然后将Page Directory的第0DirectoryEntry设为指向此Page Table所在的基地址。其它的线性地址没有被使用,所以不需要再建其它的Page Table,而将PageDirectory中的其它Directory Entry设为空。种情况下,表所占据的空就是4 KB*3=12 KB。而如果使用1级页表,即使是变长的,也需要3M+4K。所以使用2级页表很大的省了表空

基于大多数程序都是几百KB或一两兆的事了更一步的表空,可以使用**或多级页表。但这样也造成一个线性地址到物理地址的转换层多。另外,于大型程序来,其占用的表空可能更多。所以,很少有系使用3以上表。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Windows操作系统中,内存分页机制是一种虚拟内存管理技术,用于将物理内存与进程的虚拟地址空间进行映射和管理。内存分页机制的核心概念是将进程的虚拟地址空间划分为固定大小的页面(通常为4KB),并将其映射到物理内存上。 Windows使用了两级的页表结构来实现内存分页机制: 1. 页面目录表(Page Directory Table):页面目录表是一个固定大小的数据结构,用于存储指向页面表的指针。每个页面目录表项(Page Directory Entry)对应着一个页面表。页面目录表通常在系统启动时创建,并且对于每个进程都有一个独立的页面目录表。 2. 页面表(Page Table):页面表是一个固定大小的数据结构,用于将虚拟地址映射到物理地址。每个页面表项(Page Table Entry)包含了虚拟地址与物理地址的对应关系。页面表通常在进程创建时动态生成,并且只包含当前进程所需的页面映射。 通过这两级的页表结构,Windows可以实现虚拟地址到物理地址的映射。当进程访问虚拟地址时,操作系统会根据页表将其转换为物理地址,并进行相应的读取或写入操作。如果所需的页面不在物理内存中,则会触发页面错误(Page Fault),操作系统会将页面从磁盘加载到物理内存中,并更新页表的映射关系。 内存分页机制的好处是可以实现虚拟内存的管理和保护。每个进程都有独立的虚拟地址空间,使得进程之间的内存不会相互干扰,同时允许操作系统灵活地分配和回收物理内存。此外,内存分页机制还支持内存权限控制、页面共享和延迟加载等功能,提高了系统的安全性和性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值