1. 简述内核在理想情况下页面分配器(page allocator)是如何分配出连续物理页面的?

使用alloc_pages()函数分配连续的物理页面,分配的页面个数只能是2的整数次幂,传入两个参数,第一个参数为分配掩码,第二个是分配阶数。

  1. 在页面分配器中,如何从分配掩码中确定哪些zone分配内存

alloc_pages()函数会调用gfp_zone(),该函数根据分配掩码计算出zoneidx并填入alloc_context结构体的.high_zoneidx成员。根据这个zoneidx来确认zone。

static inline enum zone_type gfp_zone(gfp_t flags)

{

enum zone_type z;

int bit = (__force int) (flags & GFP_ZONEMASK);

z = (GFP_ZONE_TABLE >> (bit * GFP_ZONES_SHIFT)) &
((1 << GFP_ZONES_SHIFT) - 1);
VM_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
return z;

}

  1. 页面分配器时按照什么方向来扫描zone的?

首先扫描函数为for_next_zone_zonelist_nodemask。

#define for_next_zone_zonelist_nodemask(zone, z, highidx, nodemask)

for (zone = z->zone;

zone;

z = next_zones_zonelist(++z, highidx, nodemask),

zone = zonelist_zone(z))

有两种zone类型,ZONE_HIGHMEM和ZONE_NORMAL两种,ZONE_HIGHMEM编号为1,ZONE_NORMAL编号为0。

_zonerefs[0]->zone_index=1

_zonerefs[1]->zone_index=0

在分配物理页面时会优先考虑ZONE_HIGHMEM,再分配ZONE_NORMAL。

首先从给定的zoneidx开始扫描,就是alloc_context结构体中的high_zoneidx成员,以分配掩码GFP_KERNEL为例,计算出的high_zoneidx为0,即_zonerefs[0],而这个节点的第一个zone是ZONE_HIGHMEM,其zone编号zone_index为1.也就是说在next_zones_zonelist运行的时候,++z,最终函数会返回ZONE_NORMAL(因为只会循环一次,扫描_zonerefs[1])。遍历ZONE_NORMAL这一个zone。

  1. 为用户进程分配物理内存,分配掩码应该选择哪个

GFP_USER或者GFP_HIGHUSER

奔跑吧Linux-内存管理思考题(2)_1024程序员节