原本由bootmem管理的内存在mem_init函数中交由伙伴系统管理。

1.free_unused_memmap_node

相邻的membank间可能存在空洞,但在bootmem阶段这些空洞页也分配了page结构体。该函数的作用是找到这些page结构体所占用的内存并且释放掉。

static void __init free_unused_memmap_node(int node, struct meminfo *mi)
-->unsigned long bank_start; //前一个membank的结束地址
-->unsigned long prev_bank_end ;//后一个membank的起始地址
-->free_memmap(node, prev_bank_end, bank_start);
-->struct page *start_pg = pfn_to_page(prev_bank_end);
-->struct page *end_pg = pfn_to_page(bank_start);
-->unsigned long pg = PAGE_ALIGN(__pa(start_pg));
-->unsigned long pgend = __pa(end_pg) & PAGE_MASK;
-->free_bootmem_node(NODE_DATA(node), pg, pgend - pg);

2.移交bootmem分配剩余的空闲页到伙伴系统

该函数返回的是返回给伙伴系统的空闲页数。

unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
{
register_page_bootmem_info_node(pgdat);
return free_all_bootmem_core(pgdat->bdata);
}

空闲页保存在全局变量totalram_pages中

/*mm/page_alloc.c*/
unsigned long totalram_pages __read_mostly;

totalram_pages += free_all_bootmem_node(pgdat);

2.1该函数的核心是free_all_bootmem_core(pgdat->bdata)

static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
-->__free_pages_bootmem(pfn_to_page(start), order);
-->释放掉bdata->node_bootmem_map所占用的内存,彻底废弃bootmem分配器

释放页到伙伴系统底层调用的两个函数是

void __free_pages(struct page *page, unsigned int order)
#define __free_page(page) __free_pages((page), 0)

可以看到,最终调用的还是__free_pages函数

void __free_pages(struct page *page, unsigned int order)
{
if (put_page_testzero(page)) {
if (order == )
free_hot_page(page);
else
__free_pages_ok(page, order);
}
}

free_hot_page流程如下

free_hot_page(page);
-->free_hot_cold_page(page, );
-->struct zone *zone = page_zone(page);
-->struct per_cpu_pages *pcp = &zone_pcp(zone, get_cpu())->pcp;
-->if (cold)
list_add_tail(&page->lru, &pcp->list);/*冷页插入队列末尾*/
else
list_add(&page->lru, &pcp->list);/*热页插入队列首*/
-->pcp->count++;
-->if (pcp->count >= pcp->high)
-->free_pages_bulk(zone, pcp->batch, &pcp->list, );
-->从队列末尾开始删除pcp->batch个页
-->__free_one_page(page, zone, order);/*把删除的页释放到伙伴系统*/

__free_pages_ok流程如下:

static void __free_pages_ok(struct page *page, unsigned int order)
-->free_one_page(page_zone(page), page, order);
-->__free_one_page(page, zone, order);

可以看出,最终调用相同的底层函数__free_one_page,这个函数的实现可以说是伙伴系统的精髓。

这里注意空闲页加入伙伴系统后要做如下的设置。

set_page_order(page, order);
-->set_page_private(page, order);/*设置page->private*/
-->__SetPageBuddy(page);/*设置page->flags*/
list_add(&page->lru,&zone->free_area[order].free_list[migratetype]);
zone->free_area[order].nr_free++;

mem_init()的更多相关文章

  1. 内存管理 初始化(四)mem_init bootmem 迁移至伙伴系统

    mm_init中执行mem_init,将原通过bootmem分配器管理的低端内存 及  通过meminfo得知的高端内存释放到伙伴系统中,最后bootmem位图本身占用的低端内存物理页也被释放进伙伴系 ...

  2. MMU工作原理

    MMU的工作原理就是把虚拟地址转换成物理地址. 虚拟地址:由编译器和连接器在定位程序时分配. 物理地址:用来访问实际的主存硬件模块. 使用虚拟存储器的系统都使用一种称为分页(paging).虚拟地址空 ...

  3. MIT 6.828 JOS学习笔记17. Lab 3.1 Part A User Environments

    Introduction 在这个实验中,我们将实现操作系统的一些基本功能,来实现用户环境下的进程的正常运行.你将会加强JOS内核的功能,为它增添一些重要的数据结构,用来记录用户进程环境的一些信息:创建 ...

  4. MIT 6.828 JOS学习笔记16. Lab 2.2

    Part 3 Kernel Address Space JOS把32位线性地址虚拟空间划分成两个部分.其中用户环境(进程运行环境)通常占据低地址的那部分,叫用户地址空间.而操作系统内核总是占据高地址的 ...

  5. MIT 6.828 JOS学习笔记15. Lab 2.1

    Lab 2: Memory Management lab2中多出来的几个文件: inc/memlayout.h kern/pmap.c kern/pmap.h kern/kclock.h kern/k ...

  6. Linux内存管理之bootmem分配器

    为什么要使用bootmem分配器,内存管理不是有buddy系统和slab分配器吗?由于在系统初始化的时候需要执行一些内存管理,内存分配的任务,这个时候buddy系统,slab分配器等并没有被初始化好, ...

  7. Linux0.11内核--内存管理之1.初始化

    [版权所有,转载请注明出处.出处:http://www.cnblogs.com/joey-hua/p/5597705.html ] Linux内核因为使用了内存分页机制,所以相对来说好理解些.因为内存 ...

  8. (三)内存 SDRAM 驱动实验 (杨铸 130 页)(勉强能懂个大概)

    SDRAM 芯片讲解: 地址: 行地址 (A0-A12) 列地址 (A0-A8)    片选信号(BA0 BA1)(L-BANK)(因为SDRAM有 4片) 两片SDRAM 连线唯一区别在 UDQM ...

  9. Linux启动过程详述

    http://www.ibm.com/developerworks/cn/linux/kernel/startup/index.html Linux启动第1步:引导内核 Linux启动第2步:内核部分 ...

随机推荐

  1. <llinux下kvm虚拟化>

    原理就是本来可能要10台物理机完成的事现在只要5台,分别在每台物理机上虚拟一台,这5太虚拟机共享一个stronge,比如有一台物理机down掉后或是要做维护,我们可以把它上面的虚拟机牵走,从而减少损失 ...

  2. 前端seo基础规范

    基本规范 TDK代码规范 A: 关键词,一般3~4个最好,要与当前页面内容相关(根据实际情况,不适宜过多堆积关键词): B: 杜绝不同URL的页面标题重复现象,作为搜索结果摘要的重要选择目标之一,一定 ...

  3. python全栈测试题(一)

    1.执行Python脚本的两种方式 如果想要永久保存代码,就要用文件的方式 如果想要调试代码,就要用交互式的方式即终端命令下和python环境中 2.Pyhton单行注释和多行注释分别用什么? pyt ...

  4. unicode字符和多字节字符的相互转换接口

    作者:朱金灿 来源:http://blog.csdn.net/clever101 发现开源代码的可利用资源真多,从sqlite3的源码中抠出了几个字符转换接口,稍微改造下了发现还挺好用的.下面是实现代 ...

  5. JS案例练习:图片切换+切换模式

    先附图: CSS样式部分: <style> *{;} body{font-family:'Microsoft YaHei';} .menu{margin:20px auto 0; widt ...

  6. 【BZOJ1088】[SCOI2005] 扫雷Mine(分类讨论)

    点此看题面 大致题意: 给你一个\(2*n\)的扫雷棋盘,现让你根据第二列的信息确定第一列有多少种摆法. 扫雷性质 听说这是一道动态规划+数学题. 其实,根据扫雷游戏的某个性质,只要确定了第一个格子是 ...

  7. Mybatis-延迟加载和缓存

    延迟加载 概念: 就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据.延迟加载也称懒加载. 好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表 ...

  8. python_67_生成器3

    import time def consumer(name): print("%s 准备吃包子啦!"%name) while True: baozi = yield print(& ...

  9. basic_double_stream_incorrect

    不合理的代码 /* * Copyright 1993-2010 NVIDIA Corporation. All rights reserved. * * NVIDIA Corporation and ...

  10. android设备局域网中快速搜索之cling方式

    cling方式就像pc端windows局域网工作组刷新显示一样,原来用过扫描ip地址的方式,可以使用就是有点慢,还有一种自己加入组广播,通过发送组广播的方式.   android设备局域网中快速搜索之 ...