linux伙伴系统(四):避免碎片(下)

3.5.2  

2. 虚拟可移动内存域

依据可移动性组织页是防止内存碎片的一种可能方法。内核还提供了另一种组织该问题的手段:虚拟内存域ZONE_MOVABLE。该机制在内核2.6.23开发期间已经并入内核,比可移动性分组框架加入内核早一个版本。与可移动性分组相反,ZONE_MOVABLE特性必须由管理员显式激活。

基本思想很简单:可用的物理内存划分为两个内存域,一个用于可移动分配,一个用于不可移动分配。这会自动防止不可移动页面向可移动内存域引入碎片。

这马上引出了另一个问题:内核如何在两个竞争的内存域之间分配可用的内存?这显然对内核要求太高,因此系统管理员必须作出决定。毕竟,人可以更好的预测计算机需要处理的场景,以及各种类型内存分配的预期分布。

(1)数据结构

Kernelcore参数用来指定用于不可移动分配的内存数量,即用于既不能回收也不能迁移的内存数量。剩余的内存用于可移动分配。在分析该参数之后,结果保存在全局变量required_kernelcore中。

还可以使用参数movablecore控制用于可移动内存分配的内存数量。Required_kernelcore的大小将会据此计算。如果有聪明人同时制定两个参数,内核会按前述方法计算required_kernelcore的值,并取指定值和计算值中较大的一个。

取决于体系结构的内核配置,ZONE_MOVABLE内存域可能位域高端或普通内存区:

enum zone_type {
#ifdef CONFIG_ZONE_DMA
        ZONE_DMA,
#endif
#ifdef CONFIG_ZONE_DMA32
        ZONE_DMA32,
#endif
        ZONE_NORMAL,
#ifdef CONFIG_HIGHMEM
        ZONE_HIGHMEM,
#endif
        ZONE_MOVABLE,
        MAX_NR_ZONES
};


与系统中所有其他的内存域相反,ZONE_MOVABLE并不关联到任何硬件上有意义的内存范围。实际上,该内存域中的内存取自高端内存域或普通内存域,因此下文中称ZONE_MOVABLE是一个虚拟内存域。

辅助函数find_zone_movable_pfns_for_nodes用于计算进入ZONE_MOVABLE的内存数量。如果kernelcoremovablecore参数都没有指定,find_zone_movable_pfns_for_nodes会使ZONE_MOVABLE保持为空,该机制处于无效状态。

谈到物理内存域提取多少内存用于ZONE_MOVABLE的问题,必须考虑如下两种情况:

A. 用于不可移动分配的内存会平均分布到所有的内存结点上

B. 只使用来自最高内存域的内存。在内存较多的32位系统上,这通常会是ZONE_HIGHMEM,但是对于64位系统,将使用ZONE_NORMALHZONE_DMA32

实际计算相当冗长,实际的结果是:

A.用于虚拟内存域ZONE_MOVABLE提取内存页的物理内存域,保存在movable_zone

B.对每个结点来说,zone_movable_pfn[node_id]表示ZONE_MOVABLEmovable_zone内存域中所得内存的起始地址。

  unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES];

内核确保这些页将满足符合ZONE_MOVABLE职责的内存分配。

(2)实现

上述描述的数据结构如何使用?类似于页面迁移性方法,分配标志起了很大的作用,具体实现后面讨论。目前只要知道所有可移动性分配都需要指定__GFP_HIGHMEM__GFP_MOVABLE即可。

由于内核依据分配标志确定进行内存分配的内存域,在设置了上述标志时,可以选择ZONE_MOVABLE内存域。这是将ZONE_MOVABLE集成到伙伴系统中所需的唯一改变!其余的可以通过所有内存域的通用例程处理。

你可能感兴趣的:(linux伙伴系统(四):避免碎片(下))