您的位置:首页 > 运维架构 > Linux

Linux内存管理总结-地址映射

2013-01-30 08:39 337 查看
Linux内存管理,各种文章介绍了很多,本文从我学习理解的角度总结成文,可能大段篇幅摘自网络文章,只是从我理解的角度,进行调整介绍的先后顺序。
讲Linux内存管理,绕不开两个术语,物理地址空间和虚拟地址空间。

物理地址空间:计算机上的能实际使用的物理地址大小,在x86这种32位架构中,物理地址一般用一个32位的数字表达,对应CPU的32个引脚.这样的话,物理内存空间就只有4G大小,范围是0x00000000到0xFFFFFFFF.一般机器也够用了,但是对于服务器来说,可能要跑N多的进程,这样4G内存就不太够用了.通过PAE(物理地址扩展技术),CPU多出了四个引脚,总共36位的数字也用于标示物理地址,因此物理地址空间也就扩大到64G大小。当然在64位架构中,物理地址空间就超大了,理论值是2的64次方。

为什么要有虚拟地址空间呢?因为一个机器上可能跑多个进程,今天跑2个进程,明天跑3个进程。不同进程之间不能互相改写内存。因为会造成不可预知的故障。如果大家都共享一个物理地址空间的,就无法保证相互之间不会影响。没有办法,只好给每个进程一块虚拟的地址空间。每个进程都做自己的自留地中任意折腾,看似拥有一个完整的地址空间,其实是被限制在相互隔离的几块物理内存上。



有了虚拟地址空间后,每个进程的内存访问就简单了,因为它认为自己独立的占用整个虚拟地址空间,从0x00000000-0Xffffffff。每个进程的虚拟地址空间4个G。

操作系统如何为每个进程营造一个虚拟地址空间呢,写到这里不禁想起骇客帝国的场景,Matrix就是为人类虚拟出一个世界,让人们乐在其中。

每个进程都认为自己有一个完整的虚拟地址空间,4G大小。当进程访问虚拟空间中的线性地址时,线性地址是被映射到某个物理地址上,这被称为地址映射。举例来说:
进程A访问其线性地址0x021FFFFF,可能实际映射到物理地址页框768的偏移量为4095的位置。
进程B访问其线性地址0x021FFFFF,可能实际映射到物理地址页框468的偏移量为2的位置。
通过地址映射,操作系统给每个进程虚拟出0x00000000-0xFFFFFFFF的地址空间,但不同进程的虚拟地址空间,对应存放到不同的物理内存上。
线性地址到物理地址的映射关系是通过页表来转换的。



常规的地址映射,采用了两级页表结构。
n 页目录表PGD(Page Directory)、

n 页表PTE(Page Table)。

可以用下图来描述虚拟地址空间中一个线性地址如何映射成物理地址空间的地址:



对应该图可以解释如下:
1) 访问虚拟地址空间中的一个线性地址,比如0x021FFFFF
2) 首先将该线性地址变为二进制,32个位。切分成三部分,分别代表不同的含义.
位数
含义
22-31
代表页目录中偏移量,页目录中对应位置的值代表一个页表的物理地址
12-21
代表页表中偏移量,页表中对应位置的值代表一个物理页框
0-11
代表页框中的偏移量,页框中对应位置即物理地址
3) 根据Cr3寄存器中存放的地址,获得本进程对应的页目录表所在的页框的物理地址。(当发生进程切换时,Linux把cr3控制寄存器的内容保存在前一个执行进程的描述符中,然后把下一个要执行进程的描述符的值装入cr3寄存器中。)。
4)页目录表中每一“项”是4字节大小,总共1024个项,每个“项”包括各种标志位和一个20位的地址描述,这20位的地址描述代表了某个页表的物理地址。也就是说一个页目录表会指向1024个页表。页表中也是1024个项,每个项又指向一个页框,每个页框的大小是4K,所以总共可寻址的物理地址空间是1024*1024*4K=4G。



通过把线性地址的22-31位转化为整数,可得到范围是0-1023的偏移量,用cr3的基地址加上这个偏移量就可以得到对应的页目录表项。从这个4字节的表项中,再抽取出11-31位转化为20位的地址信息,这20位地址信息代表了一个页表所在页框的地址(因为页框是4K大小对齐的。所以页框的物理地址后12位为0,通过追加12个0,就能把20位地址补充成32位地址)。
5) 同样道理,通过把线性地址的11-21位转化为整数,可得到范围是0-1023的偏移量,用刚才获得的页表所在页框地址加上这个偏移量,就可以获得一个页表项。从这个4字节的页表项中(结构与页目录项一致)取出11-31位部分数据,转化为一个20位的地址信息,再追加12个0,就能把20位地址补充成32位地址。这个地址就是一个4k大小页框的地址。
6) 在使用线性地址的0-11位转化为整数,可得到范围是0-4095的偏移量,用刚刚获得的页框地址加上这个偏移量,就可获得一个物理地址.这个物理地址存放的内容就是线性地址寄存的内容。如果这个地址存放的是“h”,那么线性地址0x021FFFFF取出来的值就是”h”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: