学习linux的内存管理(二)

来源:互联网 发布:就只有淘宝网打不开 编辑:程序博客网 时间:2024/05/18 04:32

在讲linux的分页机制之前,先讲一下硬件的内存分页机制,从而体现linux在分页机制中的巧妙之处。

Cpu的内存分页机制

每个用户进程可以访问4G的线性空间,而这4G的空间是虚拟的,而分页机制就是将线性地址映射到物理地址上,对于4G的线性空间,我们用页为单位对其进行划分,每个页的大小为4KB,那么虚拟地址空间就可以有2^20个这样的页。若是将其保存在一个数组里,就是一个长度为2^20的数组,每个元素的值就对应一个页的初始地址,大小为4Bytes,那么要保存这样一个数组,就需要2^20*4Bytes=4MB的内存空间。(另一类,我们称之为物理页,或者是页框、页桢的。是分页单元把所有的物理内存也划分为固定长度的管理单位,它的长度一般与内存页是一一对应的)

为了节省空间,引入了一个二级管理模式的机器来组织分页单元。文字描述太累,看图直观一些:

1,  分页机制当中,页目录是唯一的,它的地址保存在CPUcr3寄存器当中,是进行地址转换的起点。

2,  这里的页目录总共有1024个目录项,这些目录项是通过页目录的地址加上线性地址的高10位来索引的,每个页目录项中保存的是每个页表的初始地址。

3,  而每个页表有1024个表项,这些表项是通过页表的地址加上线性地址的中间10位来索引的,每个表项中保存的是每个页的起始地址。

4,  将页的起始地址与线性地址中最后12位相加,得到最终我们想要的物理地址

 

1,这个转换过程,应该说还是非常简单地。全部由硬件完成,虽然多了一道手续,但是节约了大量的内存,还是值得的。那么再简单地验证一下:

这样的二级模式是否仍能够表示4G的地址;

页目录共有:2^10项,也就是说有这么多个页表

每个页表对应了:2^10页;

每个页中可寻址:2^12个字节。

还是2^32 = 4GB

2,虽然页目录和页表中的项,都是4个字节,32位,但是它们都只用高20位,低12位屏蔽为0——把页表项的低12屏蔽为0,是很好理解的,因为这样,它刚好和一个页大小对应起来,大家都成整数增加。计算起来就方便多了。但是,为什么同时也要把页目录项低12位屏蔽掉呢?因为按同样的道理,只要屏蔽其低10位就可以了,不过我想,因为12>10,这样,可以让页目录和页表使用相同的数据结构,方便。

 

Linux的页式内存管理
原理上来讲,Linux只需要为每个进程分配好所需数据结构,放到内存中,然后在调度进程的时候,切换寄存器cr3,剩下的就交给硬件来完成了(呵呵,事实上要复杂得多,不过偶只分析最基本的流程)。

前面说了i386的二级页管理架构,不过有些CPU,还有三级,甚至四级架构,Linux为了在更高层次提供抽像,为每个CPU提供统一的界面。提供了一个四层页管理架构,来兼容这些二级、三级、四级管理架构的CPU

这四级分别为:

页全局目录PGD(对应刚才的页目录)

页上级目录PUD(新引进的)

页中间目录PMD(也就新引进的)

页表PT(对应刚才的页表)。

 

整个转换依据硬件转换原理,只是多了二次数组的索引罢了,如下图:


那么,对于使用二级管理架构32位的硬件,现在又是四级转换了,它们怎么能够协调地工作起来呢?嗯,来看这种情况下,怎么来划分线性地址吧!

从硬件的角度,32位地址被分成了三部份——也就是说,不管理软件怎么做,最终落实到硬件,也只认识这三位老大。

从软件的角度,由于多引入了两部份,,也就是说,共有五部份。要让二层架构的硬件认识五部份也很容易,在地址划分的时候,将页上级目录和页中间目录的长度设置为0就可以了。
这样,操作系统见到的是五部份,硬件还是按它死板的三部份划分,也不会出错,也就是说大家共建了和谐计算机系统。

这样,虽说是多此一举,但是考虑到64位地址,使用四层转换架构的CPU,我们就不再把中间两个设为0了,这样,软件与硬件再次和谐——抽像就是强大呀!!!

例如,一个逻辑地址已经被转换成了线性地址,0x08147258,换成二制进,也就是:

0000100000 0101000111 001001011000

内核对这个地址进行划分

PGD = 0000100000

PUD = 0

PMD = 0

PT = 0101000111

offset = 001001011000

 

现在来理解Linux针对硬件的花招,因为硬件根本看不到所谓PUD,PMD,所以,本质上要求PGD索引,直接就对应了PT的地址。而不是再到PUDPMD中去查数组(虽然它们两个在线性地址中,长度为02^0 =1,也就是说,它们都是有一个数组元素的数组),那么,内核如何合理安排地址呢?

从软件的角度上来讲,因为它的项只有一个,32位,刚好可以存放与PGD中长度一样的地址指针。那么所谓先到PUD,到到PMD中做映射转换,就变成了保持原值不变,一一转手就可以了。这样,就实现了逻辑上指向一个PUD,再指向一个PDM,但在物理上是直接指向相应的PT的这个抽像,因为硬件根本不知道有PUDPMD这个东西

然后交给硬件,硬件对这个地址进行划分,看到的是:

页目录 = 0000100000

页表= 0101000111

偏移量= 001001011000

嗯,先根据0000100000(32),在页目录数组中索引,找到其元素中的地址,取其高20位,找到页表的地址,页表的地址是由内核动态分配的,接着,再加一个offset,就是最终的物理地址了。

 

原创粉丝点击