📄 -+
字号:
地址空间匹配。被操作系统用于清洗转换缓冲中的某些入口。
KRE
运行在核心模式下的代码可以读此页面。
URE
运行在用户模式下的代码可以读此页面。
GH
将整个块映射到单个而不是多个转换缓冲时的隐含粒度。
KWE
运行在核心模式下的代码可以写此页面。
UWE
运行在用户模式下的代码可以写此页面。
page frame number
对于V位置位的PTE,此域包含了对应此PTE的物理页面框号;对于无效PTE,此域不为0,它包含了页面在交换文件中位置的信息。
以下两位由Linux定义并使用。
_PAGE_DIRTY
如果置位,此页面要被写入交换文件。
_PAGE_ACCESSED
Linux用它表示页面已经被访问过。
3.2 高速缓冲
如果用上述理论模型来实现一个系统,它可能可以工作,但效率不会高。操作系统设计者和处理器设计者都在努力以提高系统的性能。除了制造更快的CPU和内存外,最好的办法是在高速缓冲中维护有用信息和数据以加快某些操作。Linux使用了许多与高速缓冲相关的内存管理策略。
Buffer Cache
这个buffer cache中包含了被块设备驱动使用的数据缓冲。
这些缓冲的单元的大小一般固定(例如说512字节)并且包含从块设备读出或者写入的信息块。块设备是仅能够以固定大小块进行读写操作的设备。所有的硬盘都是块设备。
利用设备标志符和所需块号作索引可以在buffer cache中迅速地找到数据。块设备只能够通过buffer cache来存取。如果数据在buffer cache中可以找到则无需从物理块设备(如硬盘)中读取,这样可以加速访问。
Page Cache
用来加速硬盘上可执行映象文件与数据文件的存取。
它每次缓冲一个页面的文件内容。页面从磁盘上读入内存后缓存在page cache中。
Swap Cache
只有修改过的页面存储在交换文件中。
只要这些页面在写入到交换文件后没有被修改,则下次此页面被交换出内存时,就不必再进行更新写操作,这些页面都可以简单的丢弃。在交换频繁发生的系统中,Swap Cache可以省下很多不必要且耗时的磁盘操作。
Hardware Caches
一个常见的hardware cache是处理器中的页表入口cache。处理器不总是直接读取页表而是在需要时缓存页面的转换。这种cache又叫做转换旁视缓冲(Translation Look-aside Buffers),它包含系统中一个或多个处理器的页表入口的缓冲拷贝。
当发出对虚拟地址的引用时,处理器试图找到相匹配的TLB入口。如果找到则直接将虚拟地址转换成物理地址并对数据进行处理。如果没有找到则向操作系统寻求帮助。处理器将向操作系统发出TLB失配信号,它使用一个特定的系统机制来将此异常通知操作系统。操作系统则为此地址匹配对产生新的TLB入口。当操作系统清除此异常时,处理器将再次进行虚拟地址转换。由于此时在TLB中已经有相应的入口,这次操作将成功。
使用高速缓存的缺点在于Linux必须消耗更多的时间和空间来维护这些缓存,并且当缓存系统崩溃时系统也将崩溃。
3.3 Linux 页表
图3.3 Linux的三级页表结构
Linux总是假定处理器有三级页表。每个页表通过所包含的下级页表的页面框号来访问。图3.3给出了虚拟地址是如何分割成多个域的,每个域提供了某个指定页表的偏移。为了将虚拟地址转换成物理地址,处理器必须得到每个域的值。这个过程将持续三次直到对应于虚拟地址的物理页面框号被找到。最后再使用虚拟地址中的最后一个域,得到了页面中数据的地址。
为了实现跨平台运行,Linux提供了一系列转换宏使得核心可以访问特定进程的页表。这样核心无需知道 页表入口的结构以及它们的排列方式。
这种策略相当成功,无论在具有三级页表结构的Alpha AXP还是两级页表的Intel X86处理器中,Linux总是使 用相同的页表操纵代码。
3.4 页面分配与回收
对系统中物理页面的请求十分频繁。例如当一个可执行映象被调入内存时,操作系统必须为其分配页面。当映象执行完毕和卸载时这些页面必须被释放。物理页面的另一个用途是存储页表这些核心数据结构。虚拟内存子系统中负责页面分配与回收的数据结构和机制可能用处最大。
系统中所有的物理页面用包含mem_map_t结构的链表mem_map来描叙,这些结构在系统启动时初始化。每个 mem_map_t描叙了一个物理页面。其中与内存管理相关的重要域如下:
count
记录使用此页面的用户个数。当这个页面在多个进程之间共享时,它的值大于1。
age
此域描叙页面的年龄,用于选择将适当的页面抛弃或者置换出内存时。
map_nr
记录本mem_map_t描叙的物理页面框号。
页面分配代码使用free_area数组来寻找和释放页面,此机制负责整个缓冲管理。另外此代码与处理器使用的页面大小和物理分页机制无关。
free_area中的每个元素都包含页面块的信息。数组中第一个元素描叙1个页面,第二个表示2个页面大小的块而接下来表示4个页面大小的块,总之都是2的次幂倍大小。list域表示一个队列头,它包含指向mem_map数组中page数据结构的指针。所有的空闲页面都在此队列中。map域是指向某个特定页面尺寸的页面组分配情况位图的指针。当页面的第N块空闲时,位图的第N位被置位。
图free-area-figure画出了free_area结构。第一个元素有个自由页面(页面框号0),第二个元素有4个页面大小的2个自由块,前一个从页面框号4开始而后一个从页面框号56开始。
3.4.1 页面分配
Linux使用Buddy算法来有效的分配与回收页面块。页面分配代码每次分配包含一个或者多个物理页面的内存块。页面以2的次幂的内存块来分配。这意味着它可以分配1个、2个和4个页面的块。只要系统中有足够的空闲页面来满足这个要求(nr_free_pages > min_free_page),内存分配代码将在free_area中寻找一个与请求大小相同的空闲块。free_area中的每个元素保存着一个反映这样大小的已分配与空闲页面 的位图。例如,free_area数组中第二个元素指向一个反映大小为四个页面的内存块分配情况的内存映象。
分配算法首先搜寻满足请求大小的页面。它从free_area数据结构的list域着手沿链来搜索空闲页面。如果没有这样请求大小的空闲页面,则它搜索两倍于请求大小的内存块。这个过程一直将持续到free_area 被搜索完或找到满足要求的内存块为止。如果找到的页面块大于请求的块则对其进行分割以使其大小与请求块匹配。由于块大小都是2的次幂所以分割过程十分简单。空闲块被连进相应的队列而这个页面块被分配给调用者。
图3.4 free_area数据结构
在图3.4中,当系统中有大小为两个页面块的请求发出时,第一个4页面大小的内存块(从页面框号4开始)将分成两个2页面大小的块。前一个,从页面框号4开始的,将分配出去返回给请求者,而后一个,从页面框号6开始,将被添加到free_area数组中表示两个页面大小的空闲块的元素1中。
3.4.2 页面回收
将大的页面块打碎进行分配将增加系统中零碎空闲页面块的数目。页面回收代码在适当时机下要将这些页面结合起来形成单一大页面块。事实上页面块大小决定了页面重新组合的难易程度。
当页面块被释放时,代码将检查是否有相同大小的相邻或者buddy内存块存在。如果有,则将它们结合起来形成一个大小为原来两倍的新空闲块。每次结合完之后,代码还要检查是否可以继续合并成更大的页面。最佳情况是系统的空闲页面块将和允许分配的最大内存一样大。
在图3.4中,如果释放页面框号1,它将和空闲页面框号0结合作为大小为2个页面的空闲块排入free_area的第一个元素中。
3.5 内存映射
映象执行时,可执行映象的内容将被调入进程虚拟地址空间中。可执行映象使用的共享库同样如此。然而可执行文件实际上并没有调入物理内存,而是仅仅连接到进程的虚拟内存。当程序的其他部分运行时引用到这部分时才把它们从磁盘上调入内存。将映象连接到进程虚拟地址空间的过程称为内存映射。
图3.5 虚拟内存区域
每个进程的虚拟内存用一个mm_struct来表示。它包含当前执行的映象(如BASH)以及指向vm_area_struct 的大量指针。每个vm_area_struct数据结构描叙了虚拟内存的起始与结束位置,进程对此内存区域的存取权限以及一组内存操作函数。这些函数都是Linux在操纵虚拟内存区域时必须用到的子程序。其中一个负责处理进程试图访问不在当前物理内存中的虚拟内存(通过页面失效)的情况。此函数叫nopage。它用在Linux试图将可执行映象的页面调入内存时。
可执行映象映射到进程虚拟地址时将产生一组相应的vm_area_struct数据结构。每个vm_area_struct数据结构表示可执行映象的一部分:可执行代码、初始化数据(变量)、未初始化数据等等。Linux支持许多标准的虚拟内存操作函数,创建vm_area_struct数据结构时有一组相应的虚拟内存操作函数与之对应。
3.6 请求换页
当可执行映象到进程虚拟地址空间的映射完成后,它就可以开始运行了。由于只有很少部分的映象调入内存,所以很快就会发生对不在物理内存中的虚拟内存区域的访问。当进程访问无有效页表入口的虚拟地址时,处理器将向Linux报告一个页面错误。
页面错误带有失效发生的虚拟地址及引发失效的访存方式。Linux必须找到表示此区域的vm_area_struct结构。对vm_area_struct数据结构的搜寻速度决定了处理页面错误的效率,而所有vm_area_struct结构是通过一种AVL(Adelson-Velskii and Landis) 树结构连在一起的。如果无法找到vm_area_struct与此失效虚拟地址的对应关系,则系统认为此进程访问了非法虚拟地址。这时Linux将向进程发送SIGSEGV信号,如果进程没有此信号的处理过程则终止运行。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -