摘要:理解和掌握Linux内核内存基本知识对学习Linux是至关重要的,Linux内核内存是学习Linux内核的基础,对于学习Linux其他方面的内容很有帮助,本文将主要介绍有关Linux内核内存两方面的内容,即内存管理机制及其改进。在内存管理机制中,主要介绍了分段机制和分页机制,它们是所有内存管理的基础,之后所有对内存管理的改进都是以分段机制和分页机制为基础的。在内存管理的改进中,介绍了三个主要的内容,即:反向映射,大内存页和在高端内存中存储页表条目。
关键词:分段机制;分页机制;反向映射;大内存页;页表条目
中图分类号:TP316文献标识码:A文章编号:1009-3044(208)30-0752-02
Linux kernel Memory Management Mechanism and Improvement
ZHAO Li-kun,YU De-hai,WANG Yang
(Changchun university of technology, Changchun 130041, China)
Abstract: Understanding and grasping Linux kernel memory basic knowledge is very important for learning Linux.Linux kernel memory is foundation of learning Linux kernel and helpful for learning other contents.This thesis primarily introduces two contents about Linux kernel memory.That is memory management and improvement.This paper primarily introduces segment and page mechanism in memory management mechanism.They are foundation for all the memory management and later improvement.This paper introduces three important contents―reverse mapping,big memory page and storing page table directory in high memory.
Key words: segment mechanism; page mechanism;reverse mapping; big memory page; storing page table directory in high memory
1 基本内存管理机制
1.1 分段机制
分段提供了一种机制,用于把处理器可寻址的线性地址空间划分成一些较小的称为段的受保护地址空间区域。段可以用来存放程序的代码,数据和堆栈,或者用来存放系统数据结构(例如TSS或LDT)。如果处理器中有多个程序或任务在运行,那么每个程序可分配各自的一套段。此时处理器就可以加强这些段之间的界限,并且确保一个程序不会通过访问另一个程序的段而干扰程序的执行。通常,每个程序都使用自己的段描述符表以及自己的段,对程序来说段能够完全是私有的,或者是程序之间共享的。对所有段以及系统上运行程序各自执行环境的访问都由硬件控制。
在内存分段系统中,一个程序的逻辑地址通过分段机制自动地映射到中间层的4GB线性地址空间中。程序每次对内存的引用都是对内存段中内存的引用。当程序引用一个内存地址时,通过把相应的段基址加到程序员看得见的逻辑地址上就形成了一个对应的线性地址。在保护模式运行方式下,段寄存器中存放的是一个段描述符表中某一描述符项在表中的索引值。索引值指定的段描述符项中含有需要寻址的内存段的基地址,表的长度值和段的访问特权级别等信息。寻址的内存位置由该段描述符项中指定的段基址值与一个段内偏移值组合而成。段的长度可变,由描述符中的内容指定。一个段可以定义的最大长度是4GB。寻址方式如图1所示。
1.2 分页机制
内存分页管理机制的基本原理是将CPU整个线性内存区域划分成4096字节为一页的内存页面.程序申请使用内存时,系统就以内存页为单位进行分配。在使用这种内存分页管理方法时,每个进程可以使用比实际内存容量大得多的连续地址空间。为了在使用分页机制的条件下把线性地址映射到容量相对很小的物理内存空间上,使用了页目录表和页表。页目录表与页表格式基本相同,都占用4个字节,并且每个页目录表或页表必须只能包含1024个页表项。因此一个页目录表或一个页表分别共占用1页内存。页目录和页表项的小区别在于页表项有个已写位D(Dirty),而页目录项则没有。
线性地址到物理地址的变换过程如图2所示。图中控制寄存器CR3保存着是当前页目录表在物理内存中的基地址。32位的线性地址被分成三个部分,分别用来在页目录表和页表中定位对应的页目录项和页表项以及在对应的物理内存页面中指定页面内的偏移位置。
2 对内存管理的改进
2.1 反向映射
在 Linux 内存管理器中,页表保持对进程使用的内存物理页的追踪,它们将虚拟页映射到物理页。在这些页中有一些可能不是长时间使用的,所以它们应该被交换出去。不过,在它们被交换出去之前,必须找到映射那个页的每一个进程,这样那些进程中相应页的页表条目才可以被更新。这是一项令人生畏的任务,因为为了确定某个页是否被某个进程映射,必须遍历每个进程的页表。随着在系统中运行的进程数量的增加,将这些页交换出去的工作量也会增加。
反向映射提供了一个发现哪些进程正在使用给定的内存物理页的机制。不再是遍历每个进程的页表,内存管理器现在为每一个物理页建立了一个链表,包含了指向当前映射那个页的每一个进程的页表条目(page-table entries, PTE)的指针。这个链表叫做 PTE 链。
PTE 链极大地提高了找到那些映射某个页的进程的速度,如图3所示。
可以证明反向映射是对 Linux 内存管理器的一个颇有价值的修改。通过这一途径,查找定位映射某个页的进程这一严重瓶颈被最小化为只需要一个简单的操作。当大型应用程序向内核请求大量内存和多个进程共享内存时,反向映射帮助系统继续有效地运行和扩展。当前还有更多对反向映射的改进正在研究中,可能会出现在未来的 Linux 内核版本中。
2.2 大内存页
典型地,内存管理器在 x86 系统上处理的内存页为 4 KB。实际的页大小是与体系结构相关的。对大部分用途来说,内存管理器以这样大小的页来管理内存是最有效的。不过,有一些应用程序要使用特别多的内存。大型数据库就是其中一个常见的例子。由于每个页都要由每个进程映射,必须创建页表条目来将虚拟地址映射到物理地址。如果您的一个进程要使用 4KB 的页来映射 1 GB 内存,这将用到 262,144 个页表条目来保持对那些页的追踪。如果每个页表条目消耗 8 个字节,那些每映射 1 GB 内存需要 2 MB 的开销。这本身就已经是非常可观的开销了,不过,如果有多个进程共享那些内存时,问题会变得更严重。在这种情况下,每个映射到同一块 1 GB 内存的进程将为页表条目付出自己 2 MB 的代价。如果有足够多的进程,内存在开销上的浪费可能会超过应用程序请求使用的内存数量。
解决这一问题的一个方法是使用更大的页。大部分新的处理器都支持至少一个小的和一个大的内存页大小。在 x86 上,大内存页的大小是 4 MB,或者,在物理地址扩展(PAE)打开的系统上是 2 MB。假定在前面的中使用页大小为 4 MB 的大内存页,同样 1 GB 内存只用 256 个页表条目就可以映射,而不需要 262,144 个。这样开销从 2 MB 变为 2,048 个字节。
大内存页的使用还可以通过减少 变换索引缓冲(translation lookaside buffer, TLB) 的失败次数来提高性能。TLB 是一种页表的高速缓存,让那些在表中列出的页可以更快地进行虚拟地址到物理地址的转换。大内存页可以用更少的实际页来提供更多的内存,相当于较小的页大小,使用的大内存页越多,就有越多的内存可以通过 TLB 引用。
2.3 在高端内存中存储页表条目
在 32 位机器上页表通常只可以存储在低端内存中。低端内存只限于物理内存的前 896 MB,同时还要满足内核其余的大部分要求。在应用程序使用了大量进程并映射了大量内存的情况下,低端内存可能很快就不够用了。
现在,在 2.6 内核中有一个配置选项叫做 Highmem PTE,让页表条目可以存放在高端内存中,释放出更多的低端内存区域给那些必须放在这里的其他内核数据结构。作为代价,使用这些页表条目的进程会稍微慢一些。不过,对于那些在大量进程在运行的系统来说,将页表存储到高端内存中可以在低端内存区域挤出更多的内存。内存区域如图4所示。
3 总结
Linux内核内存管理机制是学习Linux内核的关键,本文所述的内存管理机制是最基本的,不过只有在深入理解了基本内存管理机制后,才会对更为复杂的内存管理机制的更好,更容易的掌握。另外,内存管理的改进远远不只本文中提到的这些特性,本文所列出的有关内存管理的改进只是目前比较典型的,之所以选择这些特别的例子,是因为它们举例说明了 Linux 2.6 内核得到了怎样的调整和增强,以便更好地处理企业级的硬件和应用程序。
参考文献:
[1] Linux Kernel Source Code[EB/OL].http:///.
[2] 吴学毅.Linux基础教程[M],北京:清华大学出版社/北京交通大学出版社,2005.
[3] 韦东山.嵌入式Linux应用开发完全手册[M],北京:人民邮电出版社,2008.
[4] 赵炯.Linux内核完全剖析[M],北京:机械工业出版社,2006.
注:本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文