Linux的linux内存管理机制制是什么样的?

内存是Linux内核所管理的最重要的资源之一内存管理系统是操作系统中最为重要的部分。对于Linux的初学者来说熟悉Linux的内存管理非常重要。

进程是运行于虚拟地址空间的一个程序可以说,任何在Linux系统下运行的程序都是进程Linux系统中包括交互进程和批处理进程。交互进程是由Shell控制和运行的既可以在前台运行,也可以在后台运行批处理进程不属于某个终端,被提交到一个队列中以便顺序执行大多数的进程都需要虚拟内存。

对于典型的Linux应用系统128MB内存是合理的选择。如果不运行X-Window系统那么在一台特殊用途的机器(比如用于调试设备驱动程序的“崩溃和烧毁”系统)上仅用8MB内存就鈳以工作。

笔者曾经做过实验在128MB和256MB下编译内核所需的时间几乎一样,都少于3分半钟(笔者的Linux发行版本是Mandrake Linux 9.1,内核2.4.21)在一个只有8MB内存的系统仩,编译需要的时间会更长一些类似Web浏览器这样的多媒体应用软件,在内存充足时会运行得更流畅特别是在一边编译程序,一边上网瀏览的时候更是如此因此,如果只有128MB内存则预期的性能会有所降低。类似地如果要开发消耗大量内存的应用程序,可能会要求更多嘚内存所以,需要多少内存由工作需求来决定

1.在命令行使用“Free”命令监控内存使用情况 #free

上面代码给出了一个256MB的RAM和512MB交换空间的系统情況。第三行输出(Mem:)显示物理内存Total列不显示核心使用的物理内存(通常大约1MB)。Used列显示被使用的内存总额(第二行不计缓冲)Free列显示全部没有使用嘚内存。Shared列显示多个进程共享的内存总额Buffers列显示磁盘缓存的当前大小。第五行(Swap:)对换空间显示的信息类似上面。如果这行为全0那么就沒有使用对换空间。在缺省的状态下free命令以千字节(也就是1024字节为单位)来显示内存使用情况。使用-h参数以字节为单位显内存使用情况;戓者使用-m参数,以兆字节为单位显示内存使用情况还可以通过-s参数,使用命令来不间断地监视内存使用情况:

这个命令将会在终端窗口Φ连续不断地报告内存的使用情况每5秒钟更新一次。

Statistics(虚拟内存统计)的缩写如果使用vmstat命令的时候没有使用任何命令行参数,将会得箌一个一次性的报告vmstat命令报告主要的活动类型有进程(procs)、内存(以千字节为单位)、交换分区(以千字节为单位)、来自块设备(硬盘驱动器)的输入輸出量、系统中断(每秒钟发生的次数),以及中央处理单元(CPU)分配给用户、系统和空闲时分别占用的比例

存储管理子系统是操作系统中最重偠的组成部分之一。在早期计算时代由于人们所需要的内存数目远远大于物理内存,因此设计出了各种各样的策略来解决此问题其中朂成功的就是虚拟内存技术,它使得系统中有限的物理内存竞争进程所需内存空间得到满足虚拟内存通过在各个进程之间共享内存,而使系统看起来有多于实际内存的内存容量Linux支持虚拟内存, 就是使用磁盘作为RAM的扩展,使可用内存相应地有效扩大核心把当前不用的内存塊存到硬盘,腾出内存给其它目的当原来的内容又要使用时,再读回内存运行于Linux的程序只看到大量的可用内存,而不关心哪部分在磁盤上当然,读写硬盘比真的内存慢(大约慢千倍)所以程序运行较慢。用做虚拟内存的这部分硬盘叫对换空间

虚拟内存技术不仅仅让我們可以使用更多的内存,它还提供了下面这些功能: 

操作系统让系统看上去有比实际内存大得多的内存空间虚拟内存可以是系统中实際物理空间的许多倍。每个进程运行在其独立的虚拟地址空间中这些虚拟空间相互之间都完全隔离开来,所以进程间不会互相影响同時,硬件虚拟内存机构可以将内存的某些区域设置成不可写这样可以保护代码与数据不会受恶意程序的干扰。 

2.公平的物理内存分配

内存管理子系统允许系统中每个运行的进程公平地共享系统中的物理内存 

尽管虚拟内存允许进程有其独立的虚拟地址空间,但有时也需偠在进程之间共享内存例如,有可能系统中有几个进程同时运行BASH命令外壳程序为了避免在每个进程的虚拟内存空间内都存在BASH程序的拷貝,较好的解决办法是系统物理内存中只存在一份BASH的拷贝并在多个进程间共享。动态库则是另外一种进程间共享执行代码的方式共享內存可用来作为进程间通信(IPC)的手段,多个进程通过共享内存来交换信息Linux支持SYSTEM V的共享内存IPC机制。 

系统中的每一个进程都有自己的虚拟地址空间这些虚拟地址空间是完全分开的,这样一个进程的运行不会影响其它进程并且硬件上的虚拟内存机制是被保护的,内存不能被寫入这样可以防止迷失的应用程序覆盖代码的数据。

5.Linux虚拟内存实现机制

Linux虚拟内存的实现需要6种机制的支持:地址映射机制、内存分配回收机制、缓存和刷新机制、请求页机制、交换机制和内存共享机制

内存管理程序通过映射机制把用户程序的逻辑地址映射到物理地址。當用户程序运行时如果发现程序中要用的虚地址没有对应的物理内存,就发出了请求页要求如果有空闲的内存可供分配,就请求分配內存(于是用到了内存的分配和回收)并把正在使用的物理页记录在缓存中(使用了缓存机制)。如果没有足够的内存可供分配那么就调用交換机制;腾出一部分内存。另外在地址映射中要通过TLB(翻译后援存储器)来寻找物理页;交换机制中也要用到交换缓存,并且把物理页内容茭换到交换文件中也要修改页表来映射文件地址。


前面我们讲解了操作系统段式存儲管理的主要内容.

  • 32位在保护方式下,其能够访问的线性地址空间可达4GB而且允许几乎不受存储空间限制的虚拟存储器程序。虚拟存储器哋址空间能够可达64TB它还提供了复杂的存储管理和硬件辅助的保护机构和增加了支持多任务操作系统的特别优化的指令。实际上64TB的虚拟哋址空间是有磁盘等外部存储器的支持下实现的。在编写程序是可以放在磁盘存储器上但在执行时,必须把程序加载到物理存储器中洏存储器管理就是要将46位虚拟地址变换成32位物理地址。

  • 将程序分成不同的段进行管理我们编程访问内存地址时,访问的其实是操作系统抽象给我们的虚拟地址通过段基址:段偏移的方式访问内存虚拟地址,极大了简化了程序员的编程结构

  • 通过硬件和操作系统的段式管悝机制,实模式下通过段基址左移四位+段内偏移保护模式下通过段选择子select从段描述符GDT/LDT表中获取到段描述符,然后对基地址和段偏移处理将虚拟地址转换为线性地址。

如果没有采用存储器分页管理机制那么我们得到的线性地址就直接对应与物理地址,否则则需要将线性地址转换为物理地址。

从80386开始所有的80x86处理器都支持分页,它通过设置CR0寄存器的PG标志启用分页当PG=0时,线性地址就被解释成物理地址


2.1 分段机制存在的问题


分段,是指将程序所需要的内存空间大小的虚拟空间通过映射机制映射到某个物理地址空间(映射的操作由硬件完成)。分段映射机制解决了之前操作系统存在的两个问题:

  • (1)地址空间没有隔离

  • (2)程序运行的地址不确定

不过分段方法存在一個严重的问题:内存的使用效率低

分段的内存映射单位是整个程序;如果内存不足,被换入换出到磁盘的空间都是整个程序的所需空间这会造成大量的磁盘访问操作,并且严重降低了运行速度.

事实上很多时候程序运行所需要的数据只是很小的一部分,加入到内存的数據大小可能会很小并没有必要整体的写入和写出.

分页机制解决了上面分段方法所存在的一个内存使用效率问题;其核心思想是系统为程序执行文件中的第x页分配了内存中的第y页,同时y页会添加到进程虚拟空间地址的映射表中(页表)这样程序就可以通过映射访问到内存页y了。

2.2 分页存储的基本内容


分页的基本方法是将地址空间人为地等分成某一个固定大小的页;每一页大小由硬件来决定戓者是由操作系统来决定(如果硬件支持多种大小的页)。目前以大小为4KB的分页是绝大多数PC操作系统的选择.

  • 逻辑空间等分为页;并从0开始编號

  • 内存空间等分为块,与页面大小相同;从0开始编号

  • 分配内存时以块为单位将进程中的若干个页分别装入

关于进程分页. 当我们把进程的虛拟地址空间按页来分割,常用的数据和代码会被装在到内存;暂时没用到的是数据和代码则保存在磁盘中需要用到的时候,再从磁盘Φ加载到内存中即可.

这里需要了解三个概念:



分页单元(paging unit)把线性地址转换成物理地址其中的一个关键任务就是把所请求的访問类型与线性地址的访问权限相比较,如果这次内存访问是无效的就产生一个缺页异常。

  • :为了更高效和更经济的管理内存线性地址被分为以固定长度为单位的组,成为页页内部连续的线性地址空间被映射到连续的物理地址中。这样内核可以指定一个页的物理地址和对应的存取权限,而不用指定全部线性地址的存取权限这里说页,同时指一组线性地址以及这组地址包含的数据

  • 页框:分页单元把所有的 RAM 分成固定长度的页框(page frame)(有时叫做物理页)每一个页框包含一个页(page),也就是说一个页框的长度与一个页的长度一致页框是主存的一部汾,因此也是一个存储区域区分一页和一个页框是很重要的,前者只是一个数据块可以存放在任何页框或磁盘中。

  • 页表:把线性地址映射到物理地址的数据结构称为页表(page table)页表存放在主存中,并在启用分页单元之前必须由内核对页表进行适当的初始化


常规4KB分页,32位的線性地址被分成3个域

线性地址的转换分为两步完成每一步都基于一种转换表,第一种转换表称为页目录表(page directory)第二种转换表称为页表(page table)。

目嘚在于减少每个进程页表所需的 RAM 的数量如果使用简单的一级页表,将需要高达220 个表项来表示每个进程的页表即时一个进程并不使用所囿的地址,二级模式通过职位进程实际使用的那些虚拟内存区请求页表来减少内存容量

每个活动的进程必须有一个页目录,但是却没有必要马上为所有进程的所有页表都分配 RAM只有在实际需要一个页表时候才给该页表分配 RAM。

页目录项和页表项有同样的结构每项都包含下媔的字段:

如果被置为1,所指的页(或页表)就在主存中;如果该标志为0则这一页不在主存中,此时这个表项剩余的位可由操作系统用于自巳的目的如果执行一个地址转换所需的页表项或页目录项中Present标志被清0,那么分页单元就把该线性地址转换所需的页表项或页目录项中Present标誌被清0那么分页单元就把该线性地址存放在控制寄存器cr2中,并产生14号异常:缺页异常
包含页框物理地址最高20位的字段。由于每一个页框有4KB的容量它的物理地址必须是4096的倍数,因此物理地址的最低12位总为0.如果这个字段指向一个页目录相应的页框就含有一个页表;如果咜指向一个页表,相应的页框就含有一页数据
每当分页单元对相应页框进行寻址时就设置这个标志当选中的页被交换出去时,这一标志僦可以由操作系统使用分页单元从来不重置这个标志,而是必须由操作系统去做
只应用于页表项中每当对一个页框进行写操作时就设置这个标志。与Accessed标志一样当选中的页被交换出去时,这一标志就可以由操作系统使用分页单元从来不重置这个标志,而是必须由操作系统去做
含有访问页或页表所需的特权级。
控制硬件高速缓存处理页或页表的方式
只应用于页目录项。如果设置为1则页目录项指的昰2MB或4MB页框。
只应用于页表项这个标志是在Pentium Pro中引入的,用来防止常用页从TLB高速缓存中刷新出去只有在cr4寄存器的页全局启用(Page Global Enable, PGE)标志置位时这個标志才起作用。

正在使用的页目录的物理地址存放在控制寄存器CR3中

了解了以上结构之后,我们看看如何从线性地址转换到物理地址的 :

  • 線性地址中的 Directory 字段决定页目录中的目录项目录项指向适当的页表

  • 线性地址中的 Table 字段又决定页表的页表项,页表项含有页所在页框的物理哋址

  • 线性地址中的 Offset 地段决定了页框内的相对位置由于 offset 为 12 为,所以一页含有 4096 字节的数据

Directory字段和Table字段都是10位长因此页目录和页表都可以多達1024项。那么一个页目录可以寻址到高达96=232个存储单元这和32位地址所期望的一样。

3.3 物理地址扩展(PAE)分页机制囷扩展分页(PSE)


处理器所支持的RAM容易受到连接到地址总线上的地址管脚树限制. 早期Intel处理器从80386到Pentium使用32位物理地址.

从理论上讲, 这样的系统可以使用高达2^32=4GB的RAM, 而实际上, 由于用户进程现行地址空间的需要, 4GB的虚拟地址按照1:3的比例划分给内核虚拟地址空间和进程虚拟地址空间. 则内核只能直接对1GB嘚线性地址空间进行寻址.

然而, 大型服务器需要大于4GB的RAM来同时运行数以钱计的进程, 所以必须扩展32位80x86架构所支持的RAM容量.

Intel通过在它的处理器上把管脚数从32增加到36满足这样的需要, 从Pentinum Pro开始, Intel所有处理器的寻址能力可达到2^36=64GB, 但是只有引入一种新的分页机制才能把32位现行地址转换为36位物理地址財能使用所增加的物理地址.

从Pentium模型开始80x86微处理器引入了扩展分页(externded paging),也叫页大小扩展[Page Size Extension], 它允许页框大小为4MB而不是4KB扩展分页用于把大段连续嘚线性地址转换成相应的物理地址,在这种情况下内核可以不用中间页表进行地址转换,从而节省内存并保留TLB项

但是Linux并没有采用这种機制

正如前面所述,通过设置页目录项的Page Size标志启用扩展分页功能在这种情况下,分页单元把32位线性地址分成两个字段:

扩展分页和正常汾页的页目录项基本相同除了
* 20位物理地址字段只有最高10位是有意义的。这是因为每一个物理地址都是在以4MB为边界的地方开始的故这个哋址的最低22位为0。

通过设置cr4处理器寄存器的PSE标志能使扩展分页与常规分页共存

Intel为了支持PAE改变了分页机制

  • 64GB的RAM被分成了2^24个页框, 页表项的物理地址字段从20位扩展到了24位. 因为PAE页表项必须包含12个标志位和24个物理地址位, 总数之和为36, 页表项大小从32位扩展到了64位, 结果, 一个4KB的页表项包含512个表项洏不是1024个表项

  • cr3控制寄存器包含一个27位的页目录指针表(PDPT)基地址字段. 因为PDPT存放在RAM的前4GB中, 并在32字节(2^5)的倍数上对其, 因此27位足以表示这种表的基地址

  • 當把线性地址映射到4KB的页时(页目录项中的PS标准清0), 32位线性地址将按照如下方式解释

指向PDPT中4个项中的一个
指向页目录中512项中的一个
指向页表中512項中的一个

* 当把现行地址映射到2MB的页时(页目录项中的PS标志置为1), 32位线性地址按照如下方式解释

指向PDPT中4个项中的一个
指向页目录中512项中的一个

總之, 一旦cr3被设置, 就可能寻址高达4GB RAM, 如果我们期望堆更多的RAM进行寻址, 就必须在cr3中放置一个新值, 或改变PDPT的内容.

但是PAE的主要问题是线性地址仍然是32位长, 这就需要内核黑客用同一线性地址映射不同的RAM区. 很显然, PAE并没有扩大进程的线性地址空间, 因为它只处理物理地址. 此外, 只有内核能够修妀进程的页表, 所以在用户态下运行的程序不可能使用大于4GB的物理地址空间. 另一方面, PAE允许内核使用容量高达64GB的RAM, 从而显著的增加系统中的进程數目

3.4 64位系统中的分页


32位处理器普遍采用两级分页然而两级分页并不适用于采用64位系统的计算机。

首先假设一个大小为4KB的標准页4KB覆盖2^12个地址,所以offset字段是12位如果我们现在决定仅仅使用64位中的48位来寻址(这个限制仍然能是我们自在地拥有256TB的寻址空间!),剩下嘚48-12=36位被分配给Table和Directory字段如果我们决定为两个字段个预留18位,那么每个进程的页目录和页表都含有2^18个项即超过256000个项。

由于这个原因所有64位处理器的硬件分页系统都使用了额外的分页级别。使用的级别数量取决于处理器的类型

与页和页表相关的特权级只有两个,因为特权甴前面“常规分页”一节中所提到的User/Supervisor标志所控制若这个标志为0,只有当CPL小于3(这意味着对于Linux而言处理器处于内核态)时才能对页寻址;若該标志为1,则总能对页寻址

此外,与段的3种存取权限(读写,执行)不同的是页的存取权限只有两种(读,写)如果页目录项或页表项的Read/Write標志等于0,说明相应的页表或页是只读的否则是可读写的。


使用4K字节大小的页每一页都有4K字节长,并在4K字节的边界上对齐即每一页嘚起始地址都能被4K整除。因此80386把4G字节的线性地址空间,划分为1G个页面每页有4K字节大小。分页机制通过把线性地址空间中的页重新定位到物理地址空间来进行管理,因为每个页面的整个4K字节作为一个单位进行映射并且每个页面都对齐4K字节的边界,因此线性地址的低12位经过分页机制直接地作为物理地址的低12位使用。

4.1 为什么使用多级页表


假设每个进程都占用了4G的线性地址空间页表囲含1M个表项,每个表项占4个字节那么每个进程的页表要占据4M的内存空间。为了节省页表占用的空间我们使用两级页表。每个进程都会被分配一个页目录但是只有被实际使用页表才会被分配到内存里面。一级页表需要一次分配所有页表空间两级页表则可以在需要的时候再分配页表空间。


两级表结构的第一级称为页目录存储在一个4K字节的页面中。页目录表共有1K个表项每个表项为4个字节,并指向第二级表线性地址的最高10位(即位31~位32)用来产生第一级的索引,由索引得到的表项中指定并选择了1K个二级表中的一个表。

两级表結构的第二级称为页表也刚好存储在一个4K字节的页面中,包含1K个字节的表项每个表项包含一个页的物理基地址。第二级页表由线性地址的中间10 位(即位21~位12)进行索引以获得包含页的物理地址的页表项,这个物理地址的高20位与线性地址的低12位形成了最后的物理地址也就是頁转化过程输出的物理地址。

  • 第31~12位是20位页表地址由于页表地址的低12位总为0,所以用高20位指出32位页表地址就可以了因此,一个页目录最哆包含1024个页表地址

  • 第0位是存在位,如果P=1表示页表地址指向的该页在内存中,如果P=0表示不在内存中。

  • 第1位是读/写位第2位是用户/管理員位,这两位为页目录项提供硬件保护当特权级为3的进程要想访问页面时,需要通过页保护检查而特权级为0的进程就可以绕过页保护。

  • 第3位是PWT(Page Write-Through)位表示是否采用写透方式,写透方式就是既写内存(RAM)也写高速缓存,该位为1表示采用写透方式

  • 第4位是PCD(Page Cache Disable)位表示是否启鼡高速缓存,该位为1表示启用高速缓存。

  • 第5位是访问位当对页目录项进行访问时,A位=1

  • 第7位是Page Size标志,只适用于页目录项如果置为1,页目錄项指的是4MB的页面请看后面的扩展分页。

  • 第9~11位由操作系统专用Linux也没有做特殊之用。

80386的每个页目录项指向一个页表页表最多含有1024个页媔项,每项4个字节包含页面的起始地址和有关该页面的信息。页面的起始地址也是4K的整数倍所以页面的低12位也留作它用.

第31~12位是20位物理頁面地址,除第6位外第0~5位及9~11位的用途和页目录项一样第6位是页面项独有的,当对涉及的页面进行写操作时D位被置1.

4GB的内存只有一个页目录,它最多有1024个页目录项每个页目录项又含有1024个页面项,因此内存一共可以分成=1M个页面。由于每个页面为4K个字节所以,存储器的夶小正好最多为4GB.

4.3 线性地址到物理地址的转换


  • 1.CR3包含着页目录的起始地址用32位线性地址的最高10位A31~A22作为页目录的页目录项的索引,将它乘以4与CR3中的页目录的起始地址相加,形成相应页表的地址

  • 2.从指定的地址中取出32位页目录项,它的低12位为0这32位是頁表的起始地址。用32位线性地址中的A21~A12位作为页表中的页面的索引将它乘以4,与页表的起始地址相加形成32位页面地址。

  • 3.将A11~A0作为相对于页媔地址的偏移量与32位页面地址相加,形成32位物理地址


从奔腾处理器开始,Intel微处理器引进了扩展分页它允许页的大小为4MB

在扩展分页的情况下,分页机制把32位线性地址分成两个域:最高10位的目录域和其余22位的偏移量。


由于在分页情况下每次存储器访問都要存取两级页表,这就大大降低了访问速度所以,为了提高速度在386中设置一个最近存取页面的高速缓存硬件机制,它 自动保持32项處理器最近使用的页面地址因此,可以覆盖128K字节的存储器地址当进行存储器访问时,先检查要访问的页面是否在高速缓存中如果在, 就不必经过两级访问了如果不在,再进行两级访问平均来说,页面高速缓存大约有98%的命中率也就是说每次访问存储器时,只有2%的凊况必须访问两级分页机构这就大大加快了速度.

专业文档是百度文库认证用户/机構上传的专业性文档文库VIP用户或购买专业文档下载特权礼包的其他会员用户可用专业文档下载特权免费下载专业文档。只要带有以下“專业文档”标识的文档便是该类文档

VIP免费文档是特定的一类共享文档,会员用户可以免费随意获取非会员用户需要消耗下载券/积分获取。只要带有以下“VIP免费文档”标识的文档便是该类文档

VIP专享8折文档是特定的一类付费文档,会员用户可以通过设定价的8折获取非会員用户需要原价获取。只要带有以下“VIP专享8折优惠”标识的文档便是该类文档

付费文档是百度文库认证用户/机构上传的专业性文档,需偠文库用户支付人民币获取具体价格由上传人自由设定。只要带有以下“付费文档”标识的文档便是该类文档

共享文档是百度文库用戶免费上传的可与其他用户免费共享的文档,具体共享方式由上传人自由设定只要带有以下“共享文档”标识的文档便是该类文档。

我要回帖

更多关于 linux内存管理机制 的文章

 

随机推荐