文档介绍:UNIX内核-内存管理机制
 
内存管理
UNIX内存管理是内核最复杂的任务之一。重要因为它用到许多CPU提供的功能,而且和这些功能关系密切。因此,在我们讨论内存管理时,先要讨论CPU及其在内存管理中的作用。
CPU执行的许多指令需要访问内存,看起来很简单,在机器代码指令中指定要提取或修改的内存单元的地址就行了。其实没有这么简单。当需要在内存中同时运行许多进程时,使每个进程都好像在它们自己的机器上运行一样就方便了。做到这一点的办法是在CPU内部完成不同形式的地址转换,将指令指定的地址(称为逻辑地址或有效地址)转换为硬件对实际内存的访问。进程按指令、数据和堆栈分成若干段每一段都有段描述符(segment descriptor)。每一段描述符包含8个字节。内容包括段开始的基地址、段的容量和段的访问权限。段的描述符集中放在段描述表中。一个CPU内部寄存器保存访问段描述符表的基地址。
除此之外,CPU还包含一组段寄存器。每个寄存器指向描述表中的一个段描述符项。如果发生了任何类型的内存访问,将选择一个CPU段寄存器(或者由访问内存的类型的隐含说明,或者由访问内存的指令的明确说明)用来进行地址计算。计算的结果得到线性地址。这里说得是每一次的内存访问,CPU都用一个内部寄存器的内容找到描述表的基地址。基地址和一个段寄存器的内容(它的最低3位的值为0)相加。相加的结果是指向描述符表的一个8字节的项的指针。注意:段的描述府项包含段在内存中的基地址,段的容量和对本段的访问权限。访问内存的指令本身也提供一个地址,这个地址是已取得段描述符的内存段内部的逻辑地址(或有效地址)。指令的逻辑地址和段的基地址相加得到线性地址。必须对线性地址进行检查,保证它落在段的范围内(不超过段的容量),并检查是否允许在段内进行请求的访问类型(读、写或执行)。如果这些检查被通过,CPU现在有了用来访问内存的地址。
我们已经看到的段描述符主表称为全程段描述表或者GDT,,可能愿意每个进程访问它自己的内存段。为满足这一要求,CPU也为每个进程提供另外一个描述符表,称为局部描述符表或者LDT,它通过GDT的项和处理机内部寄存器LDTR进行访问。
如果每次内存访问都要查找描述符表(它本身又在内存中)的值,这将消耗大量的CPU时间。为了大大加速这一过程,CPU内部有一些隐藏的,不能由程序直接访问的寄存器。这些寄存器用作快速缓存,保存当前每个段寄存器所指的段描述符的值。只有有关的段寄存器的值改变时,或者描述符表的GDTR或LDTR的基地址改变时,才用相应的段描述符值加载隐藏的寄存器。
 
在前面讨论的组织内存访问的功能的基础上,可以建立起一个完全切实可行的多任务系统。只要在开始运行时每个进程知道它实际需要的内存容量,一开始就可以为这一进程在合适的位置分配它所需的内存块。在进程存在期间也不用再改变内存的分配。然而,有些UNIX版本要比上面的简单模型更为灵活。例如,它允许进程不必考虑周围实际上还有其他的进程存在的现实而增加它的内存要求。有的UNIX系统还允许同时运行比实际内存所能容纳的更多的进程。之所以能这样做,因为利用了处理机提供的分页(paging)功能。在CPU中是否进行调页由处理机控制寄存器中的