linux虚拟内存详解(MMU、页表结构)

Linux 的虚拟内存管理有几个关键概念:

1、每个进程都有独立的虚拟地址空间,进程访问的虚拟地址并不是真正的物理地址;
2、虚拟地址可通过每个进程上的页表(在每个进程的内核虚拟地址空间)与物理地址进行映射,获得真正物理地址;
3、如果虚拟地址对应物理地址不在物理内存中,则产生缺页中断,真正分配物理地址,同时更新进程的页表;如果此时物理内存已耗尽,则根据内存替换算法淘汰部分页面至物理磁盘中。
在这里插入图片描述
在这里插入图片描述

https://www.cnblogs.com/WindSun/p/11328820.html

32 位系统有4G 的地址空间::

  其中 0x08048000~0xbfffffff 是用户空间,0xc0000000~0xffffffff 是内核空间,包括内核代码和数据、与进程相关的数据结构(如页表、内核栈)等。另外,%esp 执行栈顶,往低地址方向变化;brk/sbrk 函数控制堆顶_edata往高地址方向变化。

在gcc编译器的实现中虚函数表vtable存放在可执行文件的只读数据段.rodata中

虚拟内存

为了运行比实际物理内存容量还要大的程序,包括Linux在内的所有现代操作系统几乎毫无例外的都采用了虚拟内存技术。虚拟内存技术,可让系统看上去具有比实际物理意义内存大的多的内存空间,并为实现多道程序的执行创造了条件。

linux的虚拟内存技术

以存储单元为单位来管理显然不现实,因此Linux把虚存空间分成若干个大小相等的存储分区,Linux把这样的分区叫做页为了换入、换出的方便,物理内存也就按也得大小分成若干个块。由于物理内存中的块空间是用来容纳虚存页的容器,所以物理内存中的块叫做页框。页与页框是Linux实现虚拟内存技术的基础

虚拟内存的页、物理内存的页框及页表
在Linux中,页与页框的大小一般为4KB。当然,根据系统和应用的不同,页与页框的大小也可有所变化。

物理内存和虚拟内存被分成了页框与页之后,其存储单元原来的地址都被自然地分成了两段,并且这两段各自代表着不同的意义:高位段分别叫做页框码和页码,它们是识别页框和页的编码;低位段分别叫做页框偏移量和页内偏移量,它们是存储单元在页框和页内的地址编码。下图就是两段虚拟内存和物理内存分页之后的情况:
在这里插入图片描述
为了使系统可以正确的访问虚存页在对应页框中的映像,在把一个页映射到某个页框上的同时,就必须把页码和存放该页映像的页框码填入一个叫做页表的表项中。这个页表就是之前提到的映射记录表。一个页表的示意图如下所示:
在这里插入图片描述
页模式下,虚拟地址、物理地址转换关系的示意图如下所示:
在这里插入图片描述
也就是说:处理器遇到的地址都是虚拟地址。虚拟地址和物理地址都分成页码(页框码)和偏移值两部分。在由虚拟地址转化成物理地址的过程中,偏移值不变。而页码和页框码之间的映射就在一个映射记录表——页表中。

请页与交换

虚存页面到物理页框的映射叫做页面的加载。

当处理器试图访问一个虚存页面时,首先到页表中去查询该页是否已映射到物理页框中,并记录在页表中。如果在,则MMU会把页码转换成页框码,并加上虚拟地址提供的页内偏移量形成物理地址后去访问物理内存;如果不在,则意味着该虚存页面还没有被载入内存,这时MMU就会通知操作系统:发生了一个页面访问错误(页面错误),接下来系统会启动所谓的“请页”机制,即调用相应的系统操作函数,判断该虚拟地址是否为有效地址。

如果是有效的地址,就从虚拟内存中将该地址指向的页面读入到内存中的一个空闲页框中,并在页表中添加上相对应的表项,最后处理器将从发生页面错误的地方重新开始运行;如果是无效的地址,则表明进程在试图访问一个不存在的虚拟地址,此时操作系统将终止此次访问

当然,也存在这样的情况:在请页成功之后,内存中已没有空闲物理页框了。这是,系统必须启动所谓地“交换”机制,即调用相应的内核操作函数,在物理页框中寻找一个当前不再使用或者近期可能不会用到的页面所占据的页框。找到后,就把其中的页移出,以装载新的页面。对移出页面根据两种情况来处理:如果该页未被修改过,则删除它;如果该页曾经被修改过,则系统必须将该页写回辅存。

系统请页的处理过程如下所示:
在这里插入图片描述
为了公平地选择将要从系统中抛弃的页面,Linux系统使用最近最少使用(LRU)页面的衰老算法。这种策略根据系统中每个页面被访问的频率,为物理页框中的页面设置了一个叫做年龄的属性。页面被访问的次数越多,则页面的年龄最小;相反,则越大。而年龄较大的页面就是待换出页面的最佳候选者。

快表

在系统每次访问虚存页时,都要在内存的所有页表中寻找该页的页框,这是一个很费时间的工作。但是,人们发现,系统一旦访问了某一个页,那么系统就会在一段时间内稳定地工作在这个页上。所以,为了提高访问页表的速度,系统还配备了一组正好能容纳一个页表的硬件寄存器,这样当系统再访问虚存时,就首先到这组硬件寄存器中去访问,系统速度就快多了。这组存放当前页表的寄存器叫做快表。

总之,使用虚拟存储技术时,处理器必须配备一些硬件来承担内存管理的一部分任务。承担内存管理任务的硬件部分叫做存储管理单元MMU。存储管理单元MMU的工作过程如下图所示:
在这里插入图片描述

页的共享

在多程序系统中,常常有多个程序需要共享同一段代码或数据的情况。在分页管理的存储器中,这个事情很好办:让多个程序共享同一个页面即可。

具体的方法是:使这些相关程序的虚拟空间的页面在页表中指向内存中的同一个页框。这样,当程序运行并访问这些相关页面时,就都是对同一个页框中的页面进行访问,而该页框中的页就被这些程序所共享。下图是3个程序共享一个页面的例子:
在这里插入图片描述

页的保护

由上可知,页表实际上是由虚拟空间转到物理空间的入口。因此,为了保护页面内容不被没有该页面访问权限的程序所破坏,就应在页表的表项中设置一些访问控制字段,用于指明对应页面中的内容允许何种操作,从而禁止非法访问。

下图是页表项中存放控制信息的一种可能的形式:
在这里插入图片描述
注意:其中的PCD位表示着是否允许高速缓存(cache)。

如果程序对一个页试图进行一个该页控制字段所不允许的操作,则会引起操作系统的一次中断——非法访问中断,并拒绝这种操作,从而保护该页的内容不被破坏。

多级页表

需要注意的是,页表是操作系统创建的用于内存管理的表格。因此,一个程序在运行时,其页表也要存放到内存空间。如果一个程序只需要一个页表,则不会有什么问题。但如果,程序的虚拟空间很大的话,就会出现一个比较大的问题。

比如:一个程序的虚拟空间为4GB,页表以4KB为一页,那么这个程序空间就是1M页。为了存储这1M页的页指针,那么这个页表的长度就相当大了,对内存的负担也很大了。所以,最好对页表也进行分页存储在程序运行时只把需要的页复制到内存,而暂时不需要的页就让它留在辅存中。为了管理这些页表页,还要建立一个记录页表页首地址的页目录表,于是单级页表就变成了二级页表。二级页表的地址转换如下图所示:
在这里插入图片描述
当然,如果程序的虚拟空间更大,那么也可以用三级页表来管理。为了具有通用性,Linux系统使用了三级页表结构:页目录(Page Directory,PGD)、中间页目录(Page Middle Directory,PMD)、页表(Page Table,PTE)

Linux的页表结构

为了通用,Linux系统使用了三级页表结构:页目录、中间页目录和页表。PGD为顶级页表,是一个pgd_t数据类型(定义在文件linux/include/page.h中)的数组,每个数组元素指向一个中间页目录;PMD为二级页表,是一个pmd_t数据结构的数组,每个数组元素指向一个页表;PTE则是页表,是一个pte_t数据类型的数组,每个元素中含有物理地址。
在这里插入图片描述
为了应用上的灵活,Linux使用一系列的宏来掩盖各种平台的细节。用户可以在配置文件config中根据自己的需要对页表进行配置,以决定是使用三级页表还是使用二级页表。

在系统编译时,会根据配置文件config中的配置,把目录include/asm符号连接到具体CPU专用的文件目录中。例如,对于i386CPU,该目录符号会连接到include/asm-i386,并在文件pgable-2level-defs.h中定义了二级页表的基本结构,如下图:

在这里插入图片描述
其中还定义了:

#define PGDIR_SHIFT 22                        //PGD在线性地址中的起始地址为bit22
#define PTRS_PER_PGD 1024                     //PGD共有1024个表项
#define PTRS_PER_PTE 1024                     //PTE共有1024个表项
#endif

在文件include/asm-i386/pgtable.h中定义了页目录和页表项的数据结构,如下:

typedof struct { unsigned long pte_low; } pte_t;                    //页表中的物理地址,页框码
typedof struct { unsigned long pgd; } pgd_t;                        //指向一个页表
typedof struct { unsigned long pgprot; } pgprot_t;                  //页表中的各个状态信息和访问权限

从定义可知,它们都是只有一个长整型类型(32位)的结构体。

注意:如上文的“页的保护”部分,页框码代表物理地址,只需要高20位就够了(因为页框的长度为4KB,因此页内偏移12位)。而后12位可以存放各个状态信息和访问权限。但是Linux并没有这样做,反而重新定义了一个结构体来存放,通过“或”运算来将两者结合。

转载自
https://blog.csdn.net/qq_38410730/article/details/81036768

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值