Bootmem
来源:互联网 发布:ipad同步软件 编辑:程序博客网 时间:2024/05/17 22:29
Bootmem是系统启动时的内存管理器,当伙伴系统初始化后,bootmem就会被free,存在时间较短,但是在伙伴系统初始化之前的内核其他初始化, 均需要依赖于bootmem,且了解bootmem能够帮助理解伙伴系统。
Bootmem使用位图来表示哪些页框被使用吗,例如系统是100兆内存,bootmem需要管理这100兆内存,一个页大小为1k,,总共102400个页(100m/1k),于是就需要102400个比特表示这些页,即需要25600个字节来存储这个位图。低n个比特为1表示该页被使用,为0表示改页未被使用。通过这种方式,来进行对物理内存进行管理,简单有效。
Bootmem初始化函数:bootmem_init
1:计算可用页的范围(最小min_low_pfn-最大max_low_pfn)。
2:计算可用页的空洞(最小-最大之间哪些区域不可用)
3:设置位图,将可用页对应的bit置为1,不可用页对应的bit置为0。
/*
* Init any data related to initrd. It's a nop if INITRD is
* not selected. Once that done we can determine the low bound
* of usable memory.
*/
reserved_end = max(init_initrd(),
(unsigned long) PFN_UP(__pa_symbol(&_end)));
计算系统需要预留的页数,这是min_low_pfn取值的判断之一。
boot_mem_map是系统启动传进来的关于内存的描述,它定义了内存哪些地址到哪些地址是可以用的,函数print_memory_map在启动时将其打印,dmesg查看,我们根据boot_mem_map来决定min_low_pfn和max_low_pfn的值。
/*
* Find the highest page frame number we have available.
*/
for (i = 0; i < boot_mem_map.nr_map; i++) {
unsigned long start, end;
if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
continue;
start = PFN_UP(boot_mem_map.map[i].addr);/*往大的取,即使浪费*/
end = PFN_DOWN(boot_mem_map.map[i].addr/*往小的取,即使浪费*/
+ boot_mem_map.map[i].size);
/*记录boot_mem_map中最小的和最大的置*/
if (end > max_low_pfn)
max_low_pfn = end;
if (start < min_low_pfn)
min_low_pfn = start;
if (end <= reserved_end)
continue;
if (start >= mapstart)
continue;
/*mapstart 用于计算位图信息存储的页的地址,当然不能和reserved_end有重叠*/
mapstart = max(reserved_end, start);
}
/*初始化bootmem*/
bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,
min_low_pfn, max_low_pfn);
init_bootmem_node:初始化bootmem_data_t
/*
* Called once to set up the allocator itself.
*/
static unsigned long __init init_bootmem_core(bootmem_data_t *bdata,
unsigned long mapstart, unsigned long start, unsigned long end)
{
unsigned long mapsize;
mminit_validate_memmodel_limits(&start, &end);
bdata->node_bootmem_map = phys_to_virt(PFN_PHYS(mapstart));/*bootmem位图的地址*/
bdata->node_min_pfn = start;/*记录min*/
bdata->node_low_pfn = end;/*记录max*/
link_bootmem(bdata);
/*
* Initially all pages are reserved - setup_arch() has to
* register free RAM areas explicitly.
*/
/*计算需要多少个字节描述start-end个页 */
mapsize = bootmap_bytes(end - start);
/*默认全部内存不可用*/
memset(bdata->node_bootmem_map, 0xff, mapsize);
bdebug("nid=%td start=%lx map=%lx end=%lx mapsize=%lx\n",
bdata - bootmem_node_data, start, mapstart, end, mapsize);
return mapsize;
}
/*计算start到end之间的空洞,核心函数是add_active_range*/
for (i = 0; i < boot_mem_map.nr_map; i++) {
unsigned long start, end;
start = PFN_UP(boot_mem_map.map[i].addr);
end = PFN_DOWN(boot_mem_map.map[i].addr
+ boot_mem_map.map[i].size);
if (start <= min_low_pfn)
start = min_low_pfn;
if (start >= end)
continue;
#ifndef CONFIG_HIGHMEM
if (end > max_low_pfn)
end = max_low_pfn;
/*
* ... finally, is the area going away?
*/
if (end <= start)
continue;
#endif
add_active_range(0, start, end);
}
/*
* Register fully available low RAM pages with the bootmem allocator.
*/
/*根据boot_mem_map,将其描述的可用内存对应的bit置0,核心函数是free_bootmem*/
for (i = 0; i < boot_mem_map.nr_map; i++) {
unsigned long start, end, size;
/*
* Reserve usable memory.
*/
if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
continue;
start = PFN_UP(boot_mem_map.map[i].addr);
end = PFN_DOWN(boot_mem_map.map[i].addr
+ boot_mem_map.map[i].size);
/*
* We are rounding up the start address of usable memory
* and at the end of the usable range downwards.
*/
if (start >= max_low_pfn)
continue;
if (start < reserved_end)
start = reserved_end;
if (end > max_low_pfn)
end = max_low_pfn;
/*
* ... finally, is the area going away?
*/
if (end <= start)
continue;
size = end - start;
/* Register lowmem ranges */
free_bootmem(PFN_PHYS(start), size << PAGE_SHIFT);
memory_present(0, start, end);
}
/*PFN_PHYS(mapstart)起的地址存在着bootmap_size个字节的位图信息,也需要保留*/
reserve_bootmem(PFN_PHYS(mapstart), bootmap_size, BOOTMEM_DEFAULT);
reserve_bootmem 和 free_bootmem都是对mark_bootmem 的封装,最后都会调用mark_bootmem_node,mark_bootmem_node会调用__reserve或者__free,里面是对bdata->node_bootmem_map前mapsize字节的地方置0或者置1。
static inline void __free_one_page(struct page *page,
struct zone *zone, unsigned int order,
int migratetype)
{
unsigned long page_idx;
unsigned long combined_idx;
unsigned long uninitialized_var(buddy_idx);
struct page *buddy;
VM_BUG_ON(!zone_is_initialized(zone));
if (unlikely(PageCompound(page)))
if (unlikely(destroy_compound_page(page, order)))
return;
VM_BUG_ON(migratetype == -1);
/*取余算法,模2048(如果MAX_ORDER是11)
*由伙伴算法知,page是从上一个order中一分为二的,故page_to_pfn(page)必是2 *的x次幂,page_idx也是2的y次幂。
*/
page_idx = page_to_pfn(page) & ((1 << MAX_ORDER) - 1);
/*暂不考虑page_index为0的情况(page_index为0,不会触发bug_on)
*如果page的order为2,则page_index最小为4,因为order为2的page必然是order *为3的page分出来的,即0-8号的page被一分为2,page_index为4。
*同理如果page的order为3,则page_index最小为8,即page_index是2^x,x>=order
*自然 2^x mod 2^order = 0
*/
VM_BUG_ON_PAGE(page_idx & ((1 << order) - 1), page);
VM_BUG_ON_PAGE(bad_range(zone, page), page);
while (order < MAX_ORDER-1) {
buddy_idx = __find_buddy_index(page_idx, order);
buddy = page + (buddy_idx - page_idx);
if (!page_is_buddy(page, buddy, order))
break;
/*
* Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page,
* merge with it and move up one order.
*/
if (page_is_guard(buddy)) {
clear_page_guard_flag(buddy);
set_page_private(page, 0);
__mod_zone_freepage_state(zone, 1 << order,
migratetype);
} else {
list_del(&buddy->lru);
zone->free_area[order].nr_free--;
rmv_page_order(buddy);
}
combined_idx = buddy_idx & page_idx;
page = page + (combined_idx - page_idx);
page_idx = combined_idx;
order++;
}
set_page_order(page, order);
/*
* If this is not the largest possible page, check if the buddy
* of the next-highest order is free. If it is, it's possible
* that pages are being freed that will coalesce soon. In case,
* that is happening, add the free page to the tail of the list
* so it's less likely to be used soon and more likely to be merged
* as a higher order page
*/
if ((order < MAX_ORDER-2) && pfn_valid_within(page_to_pfn(buddy))) {
struct page *higher_page, *higher_buddy;
combined_idx = buddy_idx & page_idx;
higher_page = page + (combined_idx - page_idx);
buddy_idx = __find_buddy_index(combined_idx, order + 1);
higher_buddy = higher_page + (buddy_idx - combined_idx);
if (page_is_buddy(higher_page, higher_buddy, order + 1)) {
list_add_tail(&page->lru,
&zone->free_area[order].free_list[migratetype]);
goto out;
}
}
list_add(&page->lru, &zone->free_area[order].free_list[migratetype]);
out:
zone->free_area[order].nr_free++;
}
- bootmem
- Bootmem
- 三读bootmem
- bootmem allocator
- Bootmem机制
- Bootmem机制
- bootmem的笔记
- bootmem_init分析(Bootmem Allocator)
- bootmem & buddy Allocator
- bootmem allocator介绍
- bootmem_init分析(Bootmem Allocator)
- bootmem allocator分析
- linux内存管理bootmem
- bootmem allocator分析
- 10. Bootmem机制
- bootmem allocator分析
- linux中bootmem分析
- 内存管理之bootmem管理之释放所有bootmem内存
- linux用户创建
- MySQL Join算法与调优白皮书
- Java8 lambda使用总结-结合实例介绍
- 小P寻宝记--好基友一起走(完全背包)
- vim快捷键
- Bootmem
- hdu red and black
- MFC实现excel的读写操作
- OpenCV 90°旋转
- ROS indigo安装完成后运行小乌龟示例程序
- matlab笔记(2)----矩阵及其运算
- html多重引号嵌套
- Oracle V$SESSION详解
- JavaScript