3.6.1 bootmem分配器

bootmem分配器使用的数据结构如下:

    include/linux/bootmem.h
    typedef struct bootmem_data {
        unsigned long node_min_pfn;
        unsigned long node_low_pfn;
        void *node_bootmem_map;
        unsigned long last_end_off;
        unsigned long hint_idx;
        struct list_head list;
    } bootmem_data_t;

下面解释结构体bootmem_data的成员。

(1)node_min_pfn是起始物理页号。

(2)node_low_pfn是结束物理页号。

(3)node_bootmem_map指向一个位图,每个物理页对应一位,如果物理页被分配,把对应的位设置为1。

(4)last_end_off是上次分配的内存块的结束位置后面一个字节的偏移。

(5)hint_idx的字面意思是“暗示的索引”,是上次分配的内存块的结束位置后面的物理页在位图中的索引,下次优先考虑从这个物理页开始分配。


每个内存节点有一个bootmem_data实例:

    include/linux/mmzone.h
    typedef struct pglist_data {
        …
    #ifndef CONFIG_NO_BOOTMEM
        struct bootmem_data *bdata;
    #endif
        …
    } pg_data_t;

bootmem分配器的算法如下。

(1)只把低端内存添加到bootmem分配器,低端内存是可以直接映射到内核虚拟地址空间的物理内存。

(2)使用一个位图记录哪些物理页被分配,如果物理页被分配,把这个物理页对应的位设置成1。

(3)采用最先适配算法,扫描位图,找到第一个足够大的空闲内存块。

(4)为了支持分配小于一页的内存块,记录上次分配的内存块的结束位置后面一个字节的偏移和后面一页的索引,下次分配时,从上次分配的位置后面开始尝试。如果上次分配的最后一个物理页的剩余空间足够,可以直接在这个物理页上分配内存。


bootmem分配器对外提供的分配内存的函数是alloc_bootmem及其变体,释放内存的函数是free_bootmem。分配内存的核心函数是源文件“mm/bootmem.c”中的函数alloc_bootmem_bdata。

ARM64架构的内核已经不使用bootmem分配器,但是其他处理器架构还在使用bootmem分配器。