linux启动内存分配器
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;
char overlap_ok;
};
/*保留内存空间全局变量*/
static struct early_res 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;
char overlap_ok;
};
/*保留内存空间全局变量*/
static struct early_res 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();
} 谢谢分享
页:
[1]