分段与分页,LDT与GDT

一个进程的地址空间,从用户的角度看,是由若干的段(segment)组成的,这些段可以分为两种:私有段(private)共享段(shared)。cpu也是按照用户的逻辑进行内存管理的(分段),Intel Pentium规定了每种段最多有8K个,每个segment最大4G。一个cpu对应有一个GDT(global descriptor table),该表详细描述了shared segment,这个表为所有进程共享的;一个process对应有一个LDT(local),该表详细描述了该process的private segment,这个表是进程私有的。


GDT/LDT的结构,每条记录有64bit:

GDT/LDT的结构
0-11  (12bit) 12-43  (32bit) 44-63  (20bit)
属性 段基址 段界限


硬件中有一个寄存器,叫做GDTR(registor),共48bit,如下:

GDTR的结构
0-31 32-47
指向GDT的开始位置 规定GDT的长度

注意:上面16bit规定了GDT的长度,该长度是指,从32bit的指针指向的GDT开始位置到GDT结束位置的绝对长度,这个长度不是表的长度,不是表的record数量。下面会说明这个绝对长度跟表的长度(表的record数量)的关系。

文章开头说了,Intel Pentium规定了每种段最多有8K个,也就是说每个GDT/LDT有8K(2^13)条record,GDTR中又规定了GDT的绝对长度是2^16,由此可以得出GDT中每个record长度为2^16 / 2^13 = 8Byte,共64bit,正好与上面GDT/LDT的结构中说明的相一致。

问题又来了,既然每个GDT/LDT可以有2^13条record,那么就需要一个至少13bit的Selector来确定是哪一条record了。事实也是这样的,一个逻辑地址包含两部分,如下:

逻辑地址的结构
0-31 32-47
段内偏移量 Segment Selector

由上可以发现,32bit的段内偏移量确实确定了每个段的大小最大为4G(如文章开头所述)。而Selector是16bit不是我们预测的13bit,事实上其结构如下:

Segment Selector的结构
0-12 13 14-15
指向GDT/LDT中的一条record 确定GDT还是LDT 操作权限

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

由以上介绍可知一个逻辑地址如何转化成为物理地址(确实可以得到一个32bit的地址,先就叫他物理地址吧,其实这个32bit的地址还要分页的)。为什么一个逻辑地址是48bit而不是32bit呢(如表“逻辑地址结构”所示)?我们在程序中如果打印一个变量的地址,确实就是一个32bit的数字啊,类似0x12345678,它并不是48bit的啊?!别忘了,我们的程序是处在一个个的Segment中的(如文章开始所述),无论是指令还是数据。我们打印出的地址其实是段内的偏移地址,程序的16bit段号由操作系统分配管理,我们是看不见的,但是的确存在。

假设一个进程需要1M的内存(指令加数据),那么os先会从LDT中选择一个段号(16bit),分给这个进程(在这个段内,我们有4G的空间可以发挥,但是我们只需要1M ^_^),如果进程有需要全局空间,os还会在GDT中为之分配的。因此..........cpu寻址的时候,也需要根据段号加段内偏移地址来找到物理地址。

注意注意注意:以上的解释中,为简单,没有说明分页!

总之,SegmentSelector(16bit)  +  段内Offset(32bit)  =  一个32bit的地址值

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

下面我告诉你,我们要对刚刚得到的32bit地址值进行分页处理,下面所有的操作都是在一个Segment内的4G空间内进行的。分页是这样分的:

操作系统为每个Segment维护一张表,称作页表,结构如下:

页表结构
0-19 20-31
页号 页内Offset
一页大小有页内偏移量就可以看出,是4K,如此为了管理4G的空间,显然这个页表需要有2^20条record。一条记录32bit=4Byte,2^20条就得需要4MB的空间啊!怎么能接受!处理的方法就是在此对0-19bit进行分页,新的页表结构如下:

二次分页的页表结构
0-9 11-19 20-32
一级页号 二级页号 页内Offset
4G空间一共有1024x1024页,第一次分页把这1024x1024页分成1024组,每组1024个,这样就需要1024张表,每张表1024条record……接着第二次分组,我们用一张表来管理这1024张表,显然着这张表也有1024条记录,如此一共有1+1024帐表,os会把不用的表交换到外存,以节省内存空间,提高查找效率。

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

综上所述,在程序中新申请一块空间,大致过程是这样的:

---->os在LDT中分配一个段号,在这个段里有4G的空间;

---->把这4G空间先分成1024份,每份大小1024 x 4K

---->把每一分再分为1024份,每份大小4K

---->把其中的一份或几份分配给申请者,并记录。


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

注:本文是新手综合课本和论坛资料原创,为加深理解,只要求逻辑正确,没有拘泥于具体细节(如具体多少bit,以及bit顺序)。它只提供了一种os管理内存的方案,并不是所以os都是这么设计的,即使是采用的这种设计,具体实现细节也因os而异。

你可能感兴趣的:(分段与分页,LDT与GDT)