- 论坛徽章:
- 0
|
linux启动内存分配器
linux启动内存分配器是在伙伴系统、slab机制实现之前,为满足内核中内存的分配而建立的。本身的机制比较简单,使用位图来进行标志分配和释放。
一、数据结构介绍
1,保留区间
因为在建立启动内存分配器的时候,会涉及保留内存。也就是说,之前保留给页表、分配器本身(用于映射的位图)、io等得内存在分配器建立后,当用它来分配内存空间时,保留出来的那些部分就不能再分配了。linux中对保留内存空间的部分用下列数据结构表示- view plaincopy to clipboardprint?/*
- * Early reserved memory areas.
- */
- #define MAX_EARLY_RES 20/*保留空间最大块数*/
-
- struct early_res {/*保留空间结构*/
- u64 start, end;
- char name[16];
- char overlap_ok;
- };
- /*保留内存空间全局变量*/
- static struct early_res early_res[MAX_EARLY_RES] __initdata = {
- { 0, PAGE_SIZE, "BIOS data page" }, /* BIOS data page */
- {}
- };
- /*
- * Early reserved memory areas.
- */
- #define MAX_EARLY_RES 20/*保留空间最大块数*/
- struct early_res {/*保留空间结构*/
- u64 start, end;
- char name[16];
- char overlap_ok;
- };
- /*保留内存空间全局变量*/
- static struct early_res early_res[MAX_EARLY_RES] __initdata = {
- { 0, PAGE_SIZE, "BIOS data page" }, /* BIOS data page */
- {}
- };2,bootmem分配器
- view plaincopy to clipboardprint?/*
- * node_bootmem_map is a map pointer - the bits represent all physical
- * memory pages (including holes) on the node.
- */
- /*用于bootmem分配器的节点数据结构*/
- typedef struct bootmem_data {
- unsigned long node_min_pfn;/*存放bootmem位图的第一个页面(即内核映象结束处的第一个页面)。*/
- unsigned long node_low_pfn;/*物理内存的顶点,最高不超过896MB。*/
- void *node_bootmem_map;
- unsigned long last_end_off;/*用来存放在前一次分配中所分配的最后一个字节相对于last_pos的位移量*/
- unsigned long hint_idx;/*存放前一次分配的最后一个页面号*/
- struct list_head list;
- } bootmem_data_t;
- /*
- * node_bootmem_map is a map pointer - the bits represent all physical
- * memory pages (including holes) on the node.
- */
- /*用于bootmem分配器的节点数据结构*/
- typedef struct bootmem_data {
- unsigned long node_min_pfn;/*存放bootmem位图的第一个页面(即内核映象结束处的第一个页面)。*/
- unsigned long node_low_pfn;/*物理内存的顶点,最高不超过896MB。*/
- void *node_bootmem_map;
- unsigned long last_end_off;/*用来存放在前一次分配中所分配的最后一个字节相对于last_pos的位移量*/
- unsigned long hint_idx;/*存放前一次分配的最后一个页面号*/
- struct list_head list;
- } bootmem_data_t;
复制代码 全局链表- view plaincopy to clipboardprint?static struct list_head bdata_list __initdata = LIST_HEAD_INIT(bdata_list);
- static struct list_head bdata_list __initdata = LIST_HEAD_INIT(bdata_list);
复制代码 二、启动分配器的建立
启动分配器的建立主要的流程为初始化映射位图、活动内存区的映射位置0(表示可用)、保留内存区域处理,其中保留区存放在上面介绍的全局数组中,这里只是将分配器中对应映射位图值1,表示已经分配。
下面我们看内核中具体的初始化流程。- start_kernel()->setup_arch()->initmem_init()
- view plaincopy to clipboardprint?void __init setup_arch(char **cmdline_p)
- {
- .......
- <span style="white-space: pre; "> </span>/*此函数在开始对bootmem分配制度建立做些准备工作
- 然后调用相关函数建立bootmem分配制度*/
- initmem_init(0, max_pfn);
- .......
- }
- void __init setup_arch(char **cmdline_p)
- {
- .......
- <span style="white-space: pre; "> </span>/*此函数在开始对bootmem分配制度建立做些准备工作
- 然后调用相关函数建立bootmem分配制度*/
- initmem_init(0, max_pfn);
- .......
- }
- view plaincopy to clipboardprint?<span style="font-family: Arial, Verdana, sans-serif; "><span style="white-space: normal; "></span></span>
- <span style="font-family: Arial, Verdana, sans-serif; "><span style="white-space: normal; "></span></span>view plaincopy to clipboardprint?<span style="font-family: Arial, Verdana, sans-serif; "><span style="white-space: normal; "></span></span><pre name="code" class="cpp">void __init initmem_init(unsigned long start_pfn,
- unsigned long end_pfn)
- {
- #ifdef CONFIG_HIGHMEM
- highstart_pfn = highend_pfn = max_pfn;
- if (max_pfn > max_low_pfn)
- highstart_pfn = max_low_pfn;
- /*将活动内存放到early_node_map中,前面已经分析过了*/
- e820_register_active_regions(0, 0, highend_pfn);
- /*设置上面变量中的内存为当前,在这里没有
- 设置相关的宏*/
- sparse_memory_present_with_active_regions(0);
- printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
- pages_to_mb(highend_pfn - highstart_pfn));
- num_physpages = highend_pfn;
- /*高端内存开始地址物理*/
- high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
- #else
- e820_register_active_regions(0, 0, max_low_pfn);
- sparse_memory_present_with_active_regions(0);
- num_physpages = max_low_pfn;
- high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
- #endif
- #ifdef CONFIG_FLATMEM
- max_mapnr = num_physpages;
- #endif
- __vmalloc_start_set = true;
-
- printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
- pages_to_mb(max_low_pfn));
- /*安装bootmem分配器,此分配器在伙伴系统起来之前
- 用来进行承担内存的分配等管理*/
- setup_bootmem_allocator();
- }
- <span style="font-family: Arial, Verdana, sans-serif; "><span style="white-space: normal; "></span></span><pre name="code" class="cpp">void __init initmem_init(unsigned long start_pfn,
- unsigned long end_pfn)
- {
- #ifdef CONFIG_HIGHMEM
- highstart_pfn = highend_pfn = max_pfn;
- if (max_pfn > max_low_pfn)
- highstart_pfn = max_low_pfn;
- /*将活动内存放到early_node_map中,前面已经分析过了*/
- e820_register_active_regions(0, 0, highend_pfn);
- /*设置上面变量中的内存为当前,在这里没有
- 设置相关的宏*/
- sparse_memory_present_with_active_regions(0);
- printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
- pages_to_mb(highend_pfn - highstart_pfn));
- num_physpages = highend_pfn;
- /*高端内存开始地址物理*/
- high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
- #else
- e820_register_active_regions(0, 0, max_low_pfn);
- sparse_memory_present_with_active_regions(0);
- num_physpages = max_low_pfn;
- high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
- #endif
- #ifdef CONFIG_FLATMEM
- max_mapnr = num_physpages;
- #endif
- __vmalloc_start_set = true;
- printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
- pages_to_mb(max_low_pfn));
- /*安装bootmem分配器,此分配器在伙伴系统起来之前
- 用来进行承担内存的分配等管理*/
- setup_bootmem_allocator();
- }
复制代码 |
|