Linux 核心--4.内存管理( 五 )



为了实现跨平台运行,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页面回收
将大的页面块打碎进行分配将增加系统中零碎空闲页面块的数目 。页面回收代码在适当时机下要将这些页面结合起来形成单一大页面块 。事实上页面块大小决定了页面重新组合的难易程度 。

推荐阅读