linux的页表为什么没有实现自映射

简介:

玩过windows内核的都应该知道windows为了节省4k的内存,实现了自映射,将页目录本身当作了一个页表来寻址4M的虚拟空间(将4M空间的虚 拟内存映射到物理内存),而这4m的虚拟地址空间恰恰就是从0xc0000000到0xc03FFFFF的空间,这一段空间正好是页表页目录的映射区域。下面我来说一下这怎么变成现实。 
首先有几点必须遵守的规则:1.一个页表映射的4m虚拟地址肯定是连续的;2.一个页表映射到的1024个4k的物理页不一定是连续的;3.实现自映射必须是页目录和页表结构一样。有了以上的规则,我们要想理解(或者自己实现一个)windows的自映射就必须理解实际上windows的页表虚拟地址都是 连续的,映射到0xc0000000到0xc03FFFFF,表现为一个页表数组,一共1024项,每项4096字节,一共正好4m,页目录作为这4m的 页表。我们反着想,如果页目录成为了这4m的页表,那么肯定映射0xc0000000到0xc03FFFFF的地址,我们将端点的两个地址分 解:11000000000000000000000000000000B和11000000001111111111111111111111B,仔细观察发现高10位是相等的,而这高10位正好是页目录项的索引,我们知道他是768,好了,页目录要作为第768页目录项对应的页表,现在这个页目录可以 作为一个页表插入到这个页表数组的第768项的位置了,它开始身兼两职了,CR3寄存器里面写的是它的物理地址,它作为页目录,此页面偏移768处也写入 了这个物理地址,它作为页表。 
现在考虑把这个页目录(页表)的虚拟映射地址换一下会怎样,别的页表不动。比如这个页目录映射到了0xdc000000这个虚拟地址(仅仅据个例子)。然 后分解地址1101110000 0000000000 000000000000,通过计算发现其对应于页目录的880项,那好吧,我把此页面880偏移改成此页面的物理地址,别的偏移处仍然指向 0xc0000000到0xc03FFFFF的虚拟地址对应的物理地址。看看会发生什么事情,如果把这个从0xc0000000到0xc03FFFFF游 离出来的页面当作页表的话,那么它所映射的虚拟地址应该连续,但是它自己是游离出来的,它的虚拟地址和别的页表的虚拟地址根本不连续,所以这样做是不可以的,也就是说对映射地址的连续性要求是一个必要的条件。windows之所以这么简单的实现了自映射,完全归功于它的设计思想,实际上一个设计并没有多么复杂,只要有了完备性,剩下的就是一个自然结果了,比如X系统是复杂的,而且它在unix出现很久以后才出现,但是unix却完美地支持了x系统,这就说 明unix很完备。windows的模块化作的很好,一致性作的也很好,它几乎将任何东西都标准化,每个进程的页表映射到同一个虚拟地址,在 windows看来,为每个进程提供一个一致的视图要比巧妙的杂糅式进程管理重要的多,所以它将虚拟地址空间作了很复杂的划分和规定。 
linux正好走了相反的路,它对于虚拟内存空间什么也没有规定,只是说了一下映射规则,提供了一套完备的机制,策略问题根本没有提及,内核虚存空间各个进程完全共享,各个数据结构散落在各处,内核空间仅仅提供了直接映射和高端映射的若干种映射规则和分配规则,至于说每个空间范围干什么用,linux只字 未提,所以说linux的页表可以散落在物理内存的任何地方,因为物理内存和虚拟内存在内核的很大一部分是一一映射的,所以上面的虚拟地址连续的要求就很难满足,比如这可能要求物理内存连续,在linux连续地址空间如此宝贵,浪费当作页表linux觉得这不值得,再说,页表可以随时分配,为什么要连续 呢?连续的话就要先预留4m页面,然后页表没有完全分配前会造成很多空洞,有几个进程能完全用完4m的页表呢?linux保守的回答了这个问题。我们看一 下代码就明白页表的分配了,代码来自最新的2.6.27内核:

int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,



 本文转自 dog250 51CTO博客,原文链接:http://blog.51cto.com/dog250/1274171

相关文章
|
2月前
|
存储 Linux
Linux下的系统编程——共享存储映射(十)
Linux下的系统编程——共享存储映射(十)
29 1
Linux下的系统编程——共享存储映射(十)
|
28天前
|
Linux Shell C语言
【Shell 命令集合 设备管理 】Linux 设置键盘映射表 loadkeys命令 使用指南
【Shell 命令集合 设备管理 】Linux 设置键盘映射表 loadkeys命令 使用指南
35 0
|
7月前
|
存储 Linux 网络虚拟化
RISC-V Linux启动之页表创建分析
RISC-V Linux启动之页表创建分析
|
5月前
|
Linux 编译器 C++
【看表情包学Linux】进程地址空间 | 区域和页表 | 虚拟地址空间 | 初识写时拷贝
【看表情包学Linux】进程地址空间 | 区域和页表 | 虚拟地址空间 | 初识写时拷贝
90 0
|
28天前
|
存储 算法 Shell
【Shell 命令集合 设备管理 】Linux 显示当前系统中定义的键盘映射表 dumpkeys命令 使用指南
【Shell 命令集合 设备管理 】Linux 显示当前系统中定义的键盘映射表 dumpkeys命令 使用指南
31 0
|
4月前
|
消息中间件 存储 缓存
Linux内存映射mmap
Linux内存映射mmap
40 0
|
5月前
|
存储 缓存 Linux
系统内存管理:虚拟内存、内存分段与分页、页表缓存TLB以及Linux内存管理
虚拟内存的主要作用是提供更大的地址空间,使得每个进程都可以拥有大量的虚拟内存,而不受物理内存大小的限制。此外,虚拟内存还可以提供内存保护和共享的机制,保护每个进程的内存空间不被其他进程非法访问,并允许多个进程共享同一份物理内存数据,提高了系统的资源利用率。虚拟内存的实现方式有分段和分页两种,其中分页机制更为常用和灵活。分页机制将虚拟内存划分为固定大小的页,将每个进程的虚拟地址空间映射到物理内存的页框中。为了减少页表的大小和访问时间,采用了多级页表的方式,将大的页表划分为多个小的页表,只加载需要的页表项,节约了内存空间。
192 0
系统内存管理:虚拟内存、内存分段与分页、页表缓存TLB以及Linux内存管理
|
9月前
|
存储 固态存储 Linux
通过Linux设备映射器使用持久内存设备
通过Linux设备映射器使用持久内存设备
81 0
|
9月前
|
Unix Linux
Linux系统应用编程---进程间通信(二)【内存共享映射mmap】
Linux系统应用编程---进程间通信(二)【内存共享映射mmap】
75 0
|
11月前
|
存储 安全 编译器
【Linux】虚拟地址空间 --- 虚拟地址、空间布局、内存描述符、写时拷贝、页表…
【Linux】虚拟地址空间 --- 虚拟地址、空间布局、内存描述符、写时拷贝、页表…