Linux 版 (精华区)
发信人: netiscpu (网中自由鸟), 信区: Linux
标 题: Linux实用教程(部分)(3)
发信站: 哈工大紫丁香 (Thu May 20 17:54:59 1999), 转信
第十章
内 存 管 理
如果读者曾经在 DOS 下开发过应用程序的话,可能会对 DOS 的 640K 常规内存限制记
忆犹新。为了在 DOS 下运行大的应用程序,人们开发了各种各样的方法,其中包括象
XMS 和 EMS 这样的内存访问规范,利用这些规范,程序可以使用 640K 之外的其他内
存。但是,这并没有从根本上解决问题。计算机中安装的内存数量各不相同,如果要在
安装有 4M 内存的计算机上运行 16M 的程序该怎么办呢?解决这一问题的办法之一就
是采用“虚拟内存”,实际上,虚拟内存是最成功的解决办法,也是流行操作系统广泛
采用的方法。
10.1 虚拟内存
虚拟内存的基本思想就是,在计算机中运行的程序,其代码、数据和堆栈的总量可以超
过实际内存的大小,操作系统只将当前使用的程序块保留在内存中,其余的程序块则保
留在磁盘上。必要时,操作系统负责在磁盘和内存之间交换程序块。
Linux 也采用虚拟内存管理机制,具体而言,虚拟内存可以提供如下好处:
大地址空间。对运行在系统中的进程而言,可用的内存总量可以超过系统的物理内存总
量,甚至可以达到好几倍。运行在 i386 平台上的 Linux 进程,其地址空间可达 4GB
。 进程保护。每个进程拥有自己的虚拟地址空间,这些虚拟地址对应的物理地址完全
和其他进程的物理地址隔离,从而避免进程之间的互相影响。 内存映射。利用内存映
射,可以将程序映象或数据文件映射到进程的虚拟地址空间中,对程序代码和数据的访
问与访问内存单元一样。 公平的物理内存分配。虚拟内存机制可保证系统中运行的进
程平等分享系统中的物理内存。 共享虚拟内存。利用虚拟内存可以方便隔离各进程的
地址空间,但是,如果将不同进程的虚拟地址映射到同一物理地址,则可实现内存共享
。这就是共享虚拟内存的本质,利用共享虚拟内存不仅可以节省物理内存的使用(如果
两个进程的部分或全部代码相同,只需在物理内存中保留一份相同的代码即可),而且
可以实现所谓“共享内存”的进程间通讯机制(两个进程通过同一物理内存区域进行数
据交换)。 Linux 中的虚拟内存采用所谓的“分页”机制。分页机制将虚拟地址空间
和物理地址空间划分为大小相同的块,这样的块称为“内存页”或简称为“页”。通过
虚拟内存地址空间的页与物理地址空间中的页之间的映射,分页机制可实现虚拟内存地
址到物理内存地址之间的转换。图 10-1 说明了两个进程的虚拟地址空间的部分页到物
理地址空间的部分页之间的映射关系。
图 10-1 虚拟地址到物理地址的映射模型
i386 平台上的 Linux 页大小为 4K 字节,而在 Alpha AXP 系统中使用 8K 字节的页
。不管是虚拟内存页还是物理内存页,它们均被给定一个唯一的“页帧编号(PFN)”
。在上述映射模型中,虚拟内存地址由两部分组成,其中一部分就是页帧编号,而另一
部分则是偏移量。CPU 负责将虚拟页帧编号翻译为相应的物理页帧编号。物理页帧编号
实际是物理地址的高位,也称为页基地址,页基地址加上偏移量就是物理内存地址(这
和 DOS 64K 段基地址及段偏移量类似)。为此,CPU 利用“页表”实现虚拟页帧编号
到物理页帧编号的转换。
如图 10-1,操作系统可以为不同的进程准备进程的私有页表,每个页表项包含物理页
帧编号、页表项的有效标志以及相应的物理页访问控制属性,访问控制属性指定了页是
只读页、只写页、可读可写页还是可执行代码页,这有利于进行内存保护,例如,进程
不能向代码页中写入数据,图 10-2 给出了 i386 系统中的页表项格式。参照图 10-1
,CPU 利用虚拟页帧编号作为访问进程页表的索引来检索页表项,如果当前页表项是有
效的,处理器就可以从该页表项中获得物理页帧编号,进而获得物理内存中的页基地址
,加上虚拟内存中的偏移量就是要访问的物理地址;如果当前页表项无效,则说明进程
访问了一个不存在的虚拟内存区,在这种情况下,CPU 将会向操作系统报告一个“页故
障”,操作系统则负责对页故障进行处理。
图 10-2 i386 系统中的页表项格式
一般而言,页故障的原因可能是因为进程访问了非法的虚拟地址,也可能是因为进程要
访问的物理地址当前不在物理内存中,这时,操作系统负责将所需的内存页装入物理内
存。
上面就是虚拟内存的抽象模型,但 Linux 中的虚拟内存机制要复杂一些。从性能的角
度考虑,如果内核本身也需要进行分页,并为内核代码和数据页维护一个页表的话,则
系统的性能会下降很多,为此,Linux 的内核运行在所谓的“物理地址模式”,CPU 不
必在这种模式下进行地址转换,物理地址模式的实现和实际的 CPU 类型有关。
10.2 Linux 的内存页表
在 i386 系统中,虚拟地址空间的大小是 4G,因此,全部的虚拟内存空间划分为 1M
页。如果用一个页表描述这种映射关系,那么这一映射表就要有 1M 个表项,当每个表
项占用 4 个字节时,全部表项占用的字节数就为 4M,为了避免占用如此巨大的内存资
源来存储页表,i386 系列 CPU 采用两级页表。类似地,Alpha AXP 系统使用三级页表
。Linux 为了避免硬件的不同细节影响内核的实施,假定有三级页表。如图 10-3 所示
,一个虚拟地址可分为多个域,不同域的数据指出了对应级别页表中的偏移量。为了将
一个虚拟地址转换为物理地址,处理器根据这三个级别域,每次将一个级别域中的值转
换为对应页表的物理页偏移量,然后从中获得下一级页表的页帧编号。如此进行三次,
就可以找出虚拟内存对应的实际物理内存。前面提到,不同 CPU 的页级数目不同,Li
nux 内核源代码则利用 C 语言的宏将具体的硬件差别隐藏了起来。例如,对 i386 的
Linux 内核代码来说,三级的页表转换宏实际只有两个在起作用。
10.3 内存页的分配和释放
系统运行过程中,经常需要进行物理内存页的分配或释放。例如,执行程序时,操作系
统需要为相应的进程分配页,而进程终止时,则要释放这些物理页。再如,页表本身也
需要动态分配和释放。物理页的分配和释放机制及其相关数据结构是虚拟内存子系统的
关键部分。
图 10-3 多级页表示意图
一般而言,有两种方法可用来管理内存的分配和释放。一种是采用位图,另外一种是采
用链表。
利用位图可记录内存单元的使用情况。例如,如果某个系统有 1024 字节内存,而内存
的分配单元是 4 字节,则可以利用 1024/(4*8) = 32 个字节来记录使用情况。这
32 个字节的每个位分别代表相应分配单元的使用情况。如果位图中某个位为 1,则对
应的分配单元是空闲的。利用这一办法,内存的分配就可以通过对位值的检测来简化。
如果一次要分配 5 个单元的空间,内存管理程序就需要找出 5 个连续位值均为 1 的
位图位置,但这种操作比较慢,因为连续的位有时要跨越字节边界。
利用链表则可以分别记录已分配的内存单元和空闲的内存单元。通常这些内存单元设计
为双向链表结构,从而可加速空闲内存的搜索或链表的处理。这种方法相对位图方法要
好一些,也更加有效。
Linux 的物理页分配采用链表和位图结合的方法。参照图 10-4,Linux 内核定义了一
个称为 free_area 的数组,该数组的每一项描述某一种页块的信息。第一个元素描述
单个页的信息,第二个元素则描述以 2 个页为一个块的页块信息,第三个元素描述以
4 个页为一个块的页块信息,依此类推,所描述的页块大小以 2 的倍数增加。free_
area 数组的每项包含两个元素:list 和 map。list 是一个双向链表的头指针,该双
向链表的每个节点包含空闲页块的起始物理页帧编号;而 map 则是记录这种页块组分
配情况的位图,例如,位图的第 N 位为 1,则表明第 N 个页块是空闲的。从图中也可
以看到,用来记录页块组分配情况的位图大小各不相同,显然页块越小,位图越大。
图 10-4 中,free_area 数组的元素 0包含了一个空闲页(页帧编号为 0);而元素
2 则包含了两个以 4 页为大小的空闲页块,第一个页块的起始页帧编号为 4,而另一
个页块的起始页帧编号为 56。
图 10-4 Linux 物理页块的分配示意
Linux 采用 Buddy 算法有效分配和释放物理页块。按照上述数据结构,Linux 可以分
配的内存大小只能是 1 个页块,2 个页块或 4 个页块等等。在分配物理页块时,Lin
ux 首先在 free_area 数组中搜索大于或等于要求尺寸的最小页块信息,然后在对应的
list 双向链表中寻找空闲页块,如果没有空闲页块,Linux 则继续搜索更大的页块信
息,直到发现一个空闲的页块为止。如果搜索到的页块大于满足要求的最小页块,则只
需将该页块剩余的部分划分为小的页块并添加到相应的 list 链表中。
页块的分配会导致内存的碎片化,而页块的释放则可以将页块重新组合成大的页块。如
果和被释放的页块大小相等的相邻页块是空闲的,则可以将这两个页块组合成一个大的
页块,这一过程一直继续,直到把所有可能的页块组合成尽可能大的页块为止。
知道了上述原理,读者可以自己想象系统启动时,初始的 free_area 数组中的信息。
10.4 内存映射和需求分页
当某个程序映象开始运行时,可执行映象必须装入进程的虚拟地址空间。如果该程序用
到了任何一个共享库,则共享库也必须装入进程的虚拟地址空间。实际上,Linux 并不
将映象装入物理内存,相反,可执行文件只是被链接到进程的虚拟地址空间中。随着程
序的运行,被引用的程序部分会由操作系统装入物理内存。这种将映象链接到进程地址
空间的方法称为“内存映射”。
每个进程的虚拟内存由一个 mm_struct 结构代表,我们将在下一章中详细讲述该结构
。该结构中实际包含了当前执行映象的有关信息,并且包含了一组指向 vm_area_stru
ct 结构的指针。如图 10-5 所示,每个 vm_area_struct 描述了一个虚拟内存区域的
起点和终点、进程对内存的访问权限以及一个对内存的操作例程集。操作例程集是 Li
nux 操作该内存区域时所使用的例程集合。例如,当进程试图访问的虚拟内存当前不在
物理内存当中时(通过页故障),Linux 就可以利用操作集中的一个例程执行正确的操
作,在这种情况下为 nopage 操作。
图 10-5 vm_area_struct 数据结构示意图
当可执行映象映射到进程的虚拟地址空间时,将产生一组 vm_area_struct 结构来描述
虚拟内存区域的起始点和终止点,每个 vm_area_struct 结构代表可执行映象的一部分
,可能是可执行代码,也可能是初始化的变量或未初始化的数据。随着 vm_area_stru
ct 结构的生成,这些结构所描述的虚拟内存区域上的标准操作函数也由 Linux 初始化
。
某个可执行映象映射到进程虚拟内存中并开始执行时,因为只有很少一部分装入了物理
内存,因此很快就会访问尚未装入物理内存的虚拟内存区域。这时,处理器将向 Linu
x 报告一个页故障及其对应的故障原因。
这种页故障的出现原因有两种,一是程序出现错误,例如向随机物理内存中写入数据,
这种情况下,虚拟内存是无效的,Linux 将向程序发送 SIGSEGV 信号并终止程序的运
行;另一种情况是,虚拟地址有效,但其所对应的页当前不在物理内存中,这时,操作
系统必须从磁盘映象或交换文件中将内存装入物理内存。
那么,Linux 如何判断页故障发生时,虚拟内存地址是否是有效的呢?如前所述,Lin
ux 利用 vm_area_struct 数据结构描述进程的虚拟内存空间,为了查找出现页故障虚
拟内存相应的 vm_area_struct 结构的位置,Linux 内核同时维护一个由 vm_area_st
ruct 结构形成的 AVL(Adelson-Velskii and Landis)树。利用 AVL 树,可快速寻找
发生页故障的虚拟地址所在的内存页区域。如果搜索不到这一内存区域,则说明该虚拟
地址是无效的,否则该虚拟地址是有效的。
也有可能因为进程在虚拟地址上进行的操作非法而产生页故障,例如在只读页中写入数
据。这时操作系统会同样发送内存错误信号到该进程。有关页的访问控制信息(只读页
、只写页、可读可写页、可执行代码页等)包含在页表项中。
对有效的虚拟地址,Linux 必须区分页所在的位置,即判断页是在交换文件中,还是在
可执行映象中。为此,Linux 通过页表项中的信息区分页所在的位置。如果该页的页表
项是无效的,但非空,则说明该页处于交换文件中,操作系统要从交换文件装入页(有
关内存交换的内容在下一节中讲述)。否则,默认情况下,Linux 会分配一个新的物理
页并建立一个有效的页表项;对于映象的内存映射来讲,则会分配新的物理页,更新页
表项属性信息,并从映象中装入页。
这时,所需的页装入了物理内存,页表项也同时被更新,然后进程就可以继续执行了。
这种只在必要时才将虚拟页装入物理内存的处理称为“需求分页”。
在处理页故障的过程中,因为要涉及到磁盘访问等耗时操作,因此操作系统会选择另外
一个进程进入执行状态。
10.5 Linux 页缓存
经内存映射的文件每次只读取一页内容,读取后的页保存在页缓存中,利用页缓存,可
提高文件的访问速度。如图 10-6 所示,页缓存由 page_hash_table 组成,它是一个
mem_map_t 数据结构的指针向量。页缓存的结构是 Linux 内核中典型的哈希表结构。
众所周知,对计算机内存的线性数组的访问是最快速的访问方法,因为线性数组中的每
一个元素的位置都可以利用索引值直接计算得到,而这种计算是简单的线性计算。但是
,如果要处理大量数据,有时由于受到存储空间的限制,采用线性结构是不切合实际的
。但如果采用链表等非线性结构,则元素的检索性能又会大打折扣。哈希表则是一种折
衷的方法,它综合了线性结构和非线性结构的优点,可以在大量数据中进行快速的查找
。哈希表的结构有多种,在 Linux 内核中,常见的哈希结构和图 10-6 的结构类似。
要在这种哈希表中访问某个数据,首先要利用哈希函数以目标元素的某个特征值作为函
数自变量生成哈希值作为索引,然后利用该索引访问哈希表的线性指针向量。哈希线性
表中的指针代表一个链表,该链表所包含的所有节点均具有相同的哈希值,在该链表中
查找可访问到指定的数据。哈希函数的选择非常重要,不恰当的哈希函数可能导致大量
数据成涞酵还V担庵智榭鱿拢氐牟檎医嗟焙氖薄5牵绻≡袂〉钡墓
:蚩梢栽谛阅芎涂占渖系玫骄庑Ч在 Linux 页缓存中,访问 page_hash
_table 的索引由文件的 VFS(虚拟文件系统)索引节点 inode 和内存页在文件中的偏
移量生成。有关 VFS 索引节点的内容将在第十三章中讲述,在这里,应知道每个文件
的 VFS 索引节点 inode 是唯一的。
图 10-6 Linux 页缓存示意图
当系统要从内存映射文件中读取某页时,首先在页缓存中查找,如果发现该页保存在缓
存中,则可以免除实际的文件读取,而只需从页缓存中读取,这时,指向 mm_map_t 数
据结构的指针被返回到页故障的处理代码;如果该页不在缓存中,则必须从实际的文件
系统映象中读取页,Linux 内核首先分配物理页然后从磁盘读取页内容。
如果可能,Linux 还会预先读取文件中下一页内容,这样,如果进程要连续访问页,则
下一页的内容不必再次从文件中读取了,而只需从页缓存中读取。
随着映象的读取和执行,页缓存中的内容可能会增多,这时,Linux 可移走不再需要的
页。当系统中可用的物理内存量变小时,Linux 也会通过缩小页缓存的大小而释放更多
的物理内存页。
10.6 内存交换
当物理内存出现不足时,Linux 内存管理子系统需要释放部分物理内存页。这一任务由
内核的交换守护进程 kswaped 完成,该内核守护进程实际是一个内核线程,它的任务
就是保证系统中具有足够的空闲页,从而使内存管理子系统能够有效运行。
在系统启动时,这一守护进程由内核的 init 进程启动。当内核的交换定时器到期时,
该进程开始运行。如果 kswaped 发现系统中的空闲页很少,该进程将按照下面的三种
方法减少系统使用的物理页:
1. 减少缓冲区和页高速缓存的大小。页高速缓存中包含内存映射文件的页,可能包含
一些系统不再需要的页,类似地,缓冲区高速缓存中也可能包含从物理设备中读取的或
写入物理设备的数据,这些缓冲区也可能不再需要,因此,这两个高速缓存可用来释放
出空闲页。但是,同时处于这两个高速缓存中的页是不能丢弃的。Linux 利用“时钟”
算法从系统中选择要丢弃的页,也即每次循环检查 mem_map 页向量中不同的页块,象
时钟的分针循环转动一样。时钟算法的原理见图 10-7。每次内核的交换进程运行时,
根据对物理内存的需求而选择不同页块大小的 mem_map 向量进行检查。如果发现某页
块处于上述两个高速缓存中,则释放相应的缓冲区,并将页块重新收入 free_area 结
构。
图 10-7 页交换的时钟算法
2. 将System V 共享内存页交换出物理内存。System V 共享内存页实际是一种进程间
通讯机制,系统通过将共享内存页交换到交换文件而释放物理内存。Linux 同样使用时
钟算法选择要交换出物理内存的页。
3. 将页交换出物理内存或丢弃。kswaped 首先选择可交换的进程,或其中某些页可从
内存中交换出或丢弃的进程。可执行映象的大部分内容可从磁盘映象中获取,因此,这
些页可丢弃。选定要交换的进程之后,Linux 将把该进程的一小部分页交换出内存,而
大部分不会被交换,另外,被锁定的页也不会被交换。Linux 利用页的寿命信息选择要
交换的页,也即所谓“最近最少使用(LRU)”算法。
页的寿命信息保存在 mem_map_t 结构中。最初分配某个页时,页的寿命为 3,每次该
页被访问,其寿命增加 3,直到 20 为至;而当内核的交换进程运行时,页寿命减 1。
如果某个页的寿命为 0,则该页可作为交换候选页。如果是“脏”页(该信息保存在页
表项中),则可将该页交换出物理内存。但是,进程的虚拟内存区域可具有自己的交换
操作例程(定义在虚拟内存操作集中),这时,将利用该例程执行交换操作,否则,交
换守护进程在交换文件中分配页,并将该页写入交换文件。
当某物理页交换到交换文件之后,该页对应的页表项被标志为无效,同时包换该页在交
换文件中的位置信息;而被释放出的物理页则被收回到 free_area 数据结构中。
根据被释放的页数目,kswaped 会自动调节交换定时器的间隔,以便能够有足够的时间
释放更多的页而保证足够的空闲页。
交换文件中的页是经过修改的页(通过在页表项中设置相应的位而标志该页为“脏”页
),则当进程再次访问该页时,操作系统必须从交换文件中将该页交换到物理内存。
10.7 高速缓存
不管在硬件设计还是软件设计中,高速缓存是获得高性能的常用手段。Linux 使用了多
种和内存管理相关的高速缓存:
缓冲区高速缓存:缓冲区高速缓存中包含了由块设备使用的数据缓冲区。这些缓冲区中
包含了从设备中读取的数据块或写入设备的数据块。缓冲区高速缓存由设备标识号和块
标号索引,因此可以快速找出数据块。如果数据能够在缓冲区高速缓存中找到,则系统
就没有必要在物理块设备上进行实际的读操作。 页高速缓存:这一高速缓存用来加速
对磁盘上的映象和数据的访问。它用来缓存某个文件的逻辑内容,并通过文件的 VFS
索引节点和偏移量访问。当页从磁盘上读到物理内存时,就缓存在页高速缓存中。 交
换高速缓存:只有修改后(脏)的页才保存在交换文件中。修改后的页写入交换文件后
,如果该页再次被交换但未被修改时,就没有必要写入交换文件,相反,只需丢弃该页
。交换高速缓存实际包含了一个页表项链表,系统的每个物理页对应一个页表项。对交
换出的页,该页表项包含保存该页的交换文件信息,以及该页在交换文件中的位置信息
。如果某个交换页表项非零,则表明保存在交换文件中的对应物理页没有被修改。如果
这一页在后续的操作中被修改,则处于交换缓存中的页表项被清零。当 Linux 需要从
物理内存中交换出某个页时,它首先分析交换缓存中的信息,如果缓存中包含该物理页
的一个非零页表项,则说明该页交换出内存后还没有被修改过,这时,系统只需丢弃该
页。 硬件高速缓存:常见的硬件缓存是对页表项的缓存,这一工作实际由处理器完成
,其操作和具体的处理器硬件有关,对这一缓存的描述已超出本书的讲述范围。 10.8
相关系统工具和系统调用
实际上,Linux 可以利用文件系统中通常的文件作为交换文件,也可以利用某个分区进
行交换操作,因此,通常把交换文件或交换分区称为“交换空间”。在交换分区上的交
换操作较快,而利用交换文件可方便改变交换空间大小。Linux 还可以使用多个交换分
区或交换文件进行交换操作。本节主要讲述有关交换空间的系统工具。
10.8.1 建立交换空间
作为交换空间的交换文件实际就是通常的文件,但文件的扇区必须是连续的,也即,文
件中必须没有“洞”,另外,交换文件必须保存在本地硬盘上。
由于内核要利用交换空间进行快速的内存页交换,因此,它不进行任何文件扇区的检查
,而认为扇区是连续的。由于这一原因,交换文件不能包含洞。可用下面的命令建立无
洞的交换文件:
$ dd if=/dev/zero of=/extra-swap bs=1024 count=2048
2048+0 records in
2048+0 records out
上面的命令建立了一个名称为 extra-swap,大小为 2048K 字节的交换文件。对 i386
系统而言,由于其页尺寸为 4K,因此最好建立一个大小为 4K 倍数的交换文件;对
Alpha AXP 系统而言,最好建立大小为 8K 倍数的交换文件。
交换分区和其他分区也没有什么不同,可象建立其他分区一样建立交换分区。但该分区
不包含任何文件系统。分区类型对内核来讲并不重要,但最好设置为 Linux Swap 类型
(即类型 82)。
建立交换文件或交换分区之后,需要在文件或分区的开头写入签名,写入的签名实际是
由内核使用的一些管理信息。写入签名的命令为 mkswap,如下所示:
$ mkswap /extra-swp 2048
Setting up swapspace, size = 2088960 bytes
$
这时,新建立的交换空间尚未开始使用。使用 mkswap 命令时必须小心,因为该命令不
会检查文件或分区内容,因此极有可能覆盖有用的信息,或破坏分区上的有效文件系统
信息。
Linux 内存管理子系统将每个交换空间的大小限制在 127M (实际为 (4096-10)*8*40
96 = 133890048 Byte = 127.6875Mb)。可以在系统中同时使用 16 个交换空间,从而
使交换空间总量达到 2GB。
10.8.2 使用交换空间
利用 swapon 命令可将经过初始化的交换空间投入使用。如下所示:
$ swapon /extra-swap
$
如果在 /etc/fstab 文件中列出交换空间,则可自动将交换空间投入使用:
/dev/hda5 none swap sw 0 0
/extra-swap none swap sw 0 0
实际上,启动脚本会运行 swapon a 命令,从而将所有出现在 /etc/fstab 文件中的交
换空间投入使用。
利用 free 命令,可查看交换空间的使用。如下所示:
$ free
total used free shared buffers
Mem: 15152 14896 256 12404 2528
-/+ buffers: 12368 2784
Swap: 32452 6684 25768
$
该命令输出的第一行(Mem: ) 显示了系统中物理内存的使用情况。total 列显示的是
系统中的物理内存总量;used 列显示正在使用的内存数量;free 列显示空闲的内存量
;shared 列显示由多个进程共享的内存量,该内存量越多越好;buffers 显示了当前
的缓冲区高速缓存的大小。
输出的最后一行 (Swap: ) 显示了有关交换空间的类似信息。如果该行的内容均为
0,表明当前没有活动的交换空间。
利用top 命令或查看 /proc 文件系统中的 /proc/meminfo 文件可获得相同的信息。
利用 swapoff 命令可移去使用中的交换空间。但该命令应只用于临时交换空间,否则
有可能造成系统崩溃。
swapoff a 命令按照 /etc/fstab 文件中的内容移去所有的交换空间,但任何手工投入
使用的交换空间保留不变。
10.8.3 分配交换空间
大多数人认为,交换空间的总量应该是系统物理内存量的两倍,实际上这一规则是不正
确的,正确的交换空间大小应按如下规则确定:
1. 估计需要的内存总量。运行想同时运行的所有程序,并利用 free 或 ps 程序估计
所需的内存总量,只需大概估计。
2. 增加一些安全性余量。
3. 减去已有的物理内存数量,然后将所得数据圆整为 MB,这就是应当的交换空间大
小。
4. 如果得到的交换空间大小远远大于物理内存量,则说明需要增加物理内存数量,否
则系统性能会因为过分的页交换而下降。
当计算的结果说明不需要任何交换空间时,也有必要使用交换空间。Linux 从性能的角
度出发,会在磁盘空闲时将某些页交换到交换空间中,以便减少必要时的交换时间。另
外,如果在不同的磁盘上建立多个交换空间,有可能提高页交换的速度,这是因为某些
硬盘驱动器可同时在不同的磁盘上进行读写操作。
10.8.4 关于缓冲区高速缓存
Linux 采用了缓冲区高速缓存机制,而不同于其他操作系统的“写透”方式,因此有可
能出现这种情况:写磁盘的命令已经返回,但实际的写操作还未执行。
基于上述原因,应当使用正常的关机命令关机,而不应直接关掉计算机的电源。用户也
可以使用 sync 命令刷新缓冲区高速缓存。在 Linux 系统中,除了传统的 update 守
护进程之外,还有一个额外的守护进程 dbflush,这一进程可频繁运行不完整的 sync
从而可避免有时由于 sync 命令的超负荷磁盘操作而造成的磁盘冻结。
dbflush 在 Linux 系统中由 update 启动。如果由于某种原因该进程僵死了,则内核
会发送警告信息,这时需要手工启动该进程(/sbin/update)。
10.8.5 系统调用
如期所述,系统调用是应用程序和内核之间的功能接口。大部分的系统调用包含在 Li
nux 的 libc 库中,通过标准的 C 函数调用方法可以调用这些系统调用。但是,少数
系统调用并没有相应的 libc 库接口,这时,可通过 syscall 系统调用使用这些系统
调用:
syscall (SYS_num, arg1, ...);
其中,SYS_num 是系统调用的编号,arg1 是该系统调用的参数。在 i386 系统中,可
最多传递 5 个系统调用参数,这和 CPU 可用的寄存器数量有关。
表 10-1 简要列出了和内存管理相关的系统调用。标志列中各字母的意义为:
m:手册页可查;
+:POSIX 兼容;
-:Linux 特有;
c:libc 包含该系统调用;
!:该系统调用和其他系统调用类似,应改用其他 POSIX 兼容系统调用。
在后面介绍系统调用时,使用相同的标志字母。
表 10-1 相关系统调用
系统调用
说明
标志
bdflush
将脏的缓冲区刷新到磁盘上
-c
brk
修改数据段(虚拟内存区域)的大小
mc
gettrlimit
获取资源限制
mc
gettrusage
获取资源使用情况
m
idle
将某个进程设置为可选择交换的进程
--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: bin@mtlab.hit.edu.cn]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:211.048毫秒