内存管理 初始化(三)before mm_init()
看到了mm_init(),期间将从bootmem迁移到伙伴系统,slab分配器也会建立。
在分析mm_init()之前,把setup_arch(&command_line)之后的函数分析了以下,详见注释。
start_kernel()
|---->page_address_init()
| 考虑支持高端内存
| 业务:初始化page_address_pool链表;
| 将page_address_maps数组元素按索引降序插入
| page_address_pool链表;
| 初始化page_address_htable数组.
|
|---->setup_arch(&command_line);
|
|---->setup_per_cpu_areas();
| 为per-CPU变量分配空间
|
|---->build_all_zonelist()
| 为系统中的zone建立后备zone的列表.
| 2.6.34中的建立过程与《深入Linux内核架构》中p_134~p_135的图不符
| (即使是UMA也不同),书中讲述是每个zone都有自己的zonelist,
| 2.6.34中对于UMA,所有zone的后备列表都在
| pglist_data->node_zonelists[]中;
|
| 期间也对per-CPU变量boot_pageset做了初始化.
|
|---->page_alloc_init()
|---->hotcpu_notifier(page_alloc_cpu_notifier, );
| 不考虑热插拔CPU
|
|---->pidhash_init()
| 详见下文.
| 根据低端内存页数和散列度,分配hash空间,并赋予pid_hash
|
|---->vfs_caches_init_early()
|---->dcache_init_early()
| dentry_hashtable空间,d_hash_shift, h_hash_mask赋值;
| 同pidhash_init();
| 区别:
| 散列度变化了( - PAGE_SHIFT);
| 传入alloc_large_system_hash的最后参数值为0;
|
|---->inode_init_early()
| inode_hashtable空间,i_hash_shift, i_hash_mask赋值;
| 同pidhash_init();
| 区别:
| 散列度变化了( - PAGE_SHIFT);
| 传入alloc_large_system_hash的最后参数值为0;
|
void pidhash_init(void)
|---->pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash),
| , , HASH_EARLY|HASH_SMALL, &pidhash_shift, NULL, );
| 根据nr_kernel_pages(低端内存的页数),分配哈希数组,以及各个哈希
| 数组元素下的哈希链表的空间,原理如下:
| number = nr_kernel_pages;
| number >= ( - PAGE_SHIFT) 根据散列度获得数组元素个数
| number = roundup_pow_of_two(number);
| pidhash_shift = max{x | **x <= number}
| size = number * sizeof(*pid_hash);
| 使用位图分配器分配size空间,将返回值付给pid_hash;
|
|---->pidhash_size = << pidhash_shift;
|
|---->for(i = ; i < pidhash_size; i++)
| INIT_HLIST_HEAD(&pid_hash[i]);
void build_all_zonelists(void)
|---->set_zonelist_order()
|---->current_zonelist_order = ZONELIST_ORDER_ZONE;
|
|---->__build_all_zonelists(NULL);
| Memory不支持热插拔, 为每个zone建立后备的zone,
| 每个zone及自己后备的zone,形成zonelist
|
|---->vm_total_pages = nr_free_pagecache_pages();
| 业务:获得所有zone中的present_pages总和.
|
|---->page_group_by_mobility_disabled = ;
| 对于代码中的判断条件一般不会成立,因为页数会最够多(内存较大)
static int __build_all_zonelists(void *dummy)
|---->pg_data_t *pgdat = NULL;
| pgdat = &contig_page_data;(单node)
|
|---->build_zonelists(pgdat);
| 为每个zone建立后备zone的列表
|
|---->build_zonelist_cache(pgdat);
|---->pdat->node_zonelists[].zlcache_ptr = NULL;
| UMA体系结构
|
|---->for_each_possible_cpu(cpu)
| setup_pageset(&per_cpu(boot_pageset, cpu), );
|详见下文
void build_zonelists(pg_data *pgdat)
|---->struct zonelist *zonelist = NULL;
| enum zone_type j;
| zonelist = &pgdat->node_zonelists[];
|
|---->j = build_zonelists_node(pddat, zonelist, , MAX_NR_ZONES - );
| 为pgdat->node_zones[]建立后备的zone,node_zones[]后备的zone
| 存储在node_zonelist[]内,对于node_zone[]的后备zone,其后备的zone
| 链表如下(只考虑UMA体系,而且不考虑ZONE_DMA):
| node_zonelist[]._zonerefs[].zone = &node_zones[];
| node_zonelist[]._zonerefs[].zone_idx = ;
| node_zonelist[]._zonerefs[].zone = &node_zones[];
| node_zonelist[]._zonerefs[].zone_idx = ;
| node_zonelist[]._zonerefs[].zone = &node_zones[];
| node_zonelist[]._zonerefs[].zone_idx = ;
|
| zonelist->_zonerefs[].zone = NULL;
| zonelist->_zonerefs[].zone_idx = ;
void setup_pageset(struct per_cpu_pageset *p, unsigned long batch)
|---->memset(p, , sizeof(*p));
|
|---->struct per_cpu_pages *pcp = NULL;
| pcp = &p->pcp;
| pcp->count = ;
| pcp->high = * batch;
| pcp->batch = max(1UL, * batch);
|
|---->for(migratetype = ;
| migratetype < MIGRATE_PCPTYPES;
| migratetype++)
|---->INIT_LIST_HEAD(&pcp->lists[migratetype]);
unsigned int nr_free_pagecache_pages(void)
|-->return nr_free_zone_pages(gfp_zone(GFP_HIGHUSER_MOVABLE));
对于UMA,且不考虑ZONE_DMA,参数为2
|-->参数offset = ;
| struct zoneref *z =NULL;
| struct zone *zone = NULL;
| unsigned int sum = ;
| struct zonelist *zonelist =
| node_zonelist(numa_node_id(), GFP_KERNEL)
| 对于UMA,zonelist =
| (&contig_page_data)->node_zonelists;
|
|-->for_each_zone_zonelist(zone, z, zonelist, offset)
| offset的作用在于遍历zonelist下的_zonerefs数组元数中,
| zone_idx <= offset的zone;
| 因此当offset为0时,遍历的结果相当于
| zone = &pglist_data->node_zones[]
|
| unsigned long size = zone->present_pages;
| 获得该zone跨越的页数.
|
| unsigned long high = high_wmark_pages(zone);
| if(size > high) sum += size - high;
| (high暂时为0,因为zone->watermark[WMARK_HIGH] = )
|
|-->return sum;
内存管理 初始化(三)before mm_init()的更多相关文章
- 内存管理 初始化(八) 至kswapd_init
至此,内存初始化部分已看完,遗留问题: 1.对于unicore或者mips的页表建立都很清楚,但是对于ARM我不清楚: 初始化部分涉及的页表映射建立,我都以unicore架构为准,ARM的页表映射从原 ...
- 垃圾回收GC:.Net自己主动内存管理 上(三)终结器
垃圾回收GC:.Net自己主动内存管理 上(三)终结器 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己主 ...
- 内存管理 初始化(五)kmem_cache_init 初始化slab分配器(上)
看了下kmem_cache_init,涉及到不同MIGRATE间的buddy system的迁移,kmem_cache的构建,slab分配器头的构建.buddy system的伙伴拆分. 对于SMP系 ...
- linux内存管理初始化
内存管理子系统是linux内核最核心最重要的一部分,内核的其他部分都需要在内存管理子系统的基础上运行.而对其初始化是了解整个内存管理子系统的基础.对相关数据结构的初始化是从全局启动例程start_ke ...
- 内存管理 初始化(六)vmalloc_init 及 ioremap
是不是我错了,本想这个函数会如网上所说将进行非连续内存管理的初始化,但是对于2.6.34的ARM架构而言,该函数实际完成的业务非常少. 内存管理的初始化读到此处,我感觉原有的认识存在很大缺陷: (1) ...
- 内存管理初始化源码4:add_active_range
我们在阅读源码时,函数功能可以分为两类:1. bootmem.c 2. page_alloc.c. 1. bootmem.c是关于bootmem allocator的,上篇文章已经简述过. 2. pa ...
- 内存管理初始化源码3:bootmem
start_kernel ——> setup_arch ——> arch_mem_init ——> bootmem_init ——> init_bootmem_node: 此时 ...
- 内存管理初始化源码2:setup_arch
PFN相关宏说明: /* kernel/include/linux/pfn.h */ PFN : Page Frame Number(物理页帧) /* * PFN_ALIGN:返回地址x所在那一页帧的 ...
- 内存管理初始化源码1:setup_arch
源码声明:基于Linux kernel 3.08 1. 在kernel/arch/mips/kernel/head.S中会做一些特定硬件相关的初始化,然后会调用内核启动函数:start_kernel: ...
随机推荐
- CSS网页布局中易犯的30个小错误
即使是CSS高手,也难免在书写CSS代码的时候出一些小错误,或者说,任何一种代码都是如此.小错误却往往造成大问题,浪费很多无辜的时间来调试和排错.查看下面这份CSS网页布局中易犯的10个小错误,努力的 ...
- JD 题目1040:Prime Number (筛法求素数)
OJ题目:click here~~ 题目分析:输出第k个素数 贴这么简单的题目,目的不清纯 用筛法求素数的基本思想是:把从1開始的.某一范围内的正整数从小到大顺序排列, 1不是素数,首先把它筛掉.剩下 ...
- Functions: C++'s Programming Modules
在这一章中要学习以下内容: 函数基础 函数原型 通过value向函数传递参数 设计处理数组的函数 使用const指针参数 设计函数处理文本字符串 设计函数处理结构体 设计函数处理string类型的对象 ...
- 采用dlopen、dlsym、dlclose dlopen dlerror加载动态链接库【总结】
.前言 为了使程序方便扩展,具备通用性,可以采用插件形式.采用异步事件驱动模型,保证主程序逻辑不变,将各个业务已动态链接库的形式加载进来,这就是所谓的插件.linux提供了加载和处理动态链接库的系统调 ...
- STM32F10x_ADC三通道DMA连续转换(3通道、软件单次触发)
Ⅰ.概述 上一篇文章讲述的内容是:三通道逐次转换(单次.单通道软件触发),也就是说3条通道要三次软件触发才能完成转换,而且是通过软件读取转换数值. 本文讲述三通道DMA连续转换(3通道.软件单次触发) ...
- String Format for Double [C#]
转载:http://www.csharp-examples.net/string-format-double/ he following examples show how to format flo ...
- SpringBoot2 全局异常处理
参考这篇文章里面的几种异常形式: 全局异常处理是个比较重要的功能,一般在项目里都会用到. 大概把一次请求分成三个阶段,来分别进行全局的异常处理. 一:在进入Controller之前,譬如请求一个不存在 ...
- Ubuntu free以及Linux内存占用大的解释
-bash-3.00$ free total used free shared buffers cached Mem: 514020 465932 48088 0 15864 348844 -/ bu ...
- Java instanceof的进一步理解
instanceof是Java的一个二元操作符,和==,>,<是同一类东东.由于它是由字母组成的,所以也是Java的保留关键字.它的作用是测试它左边的对象是否是它右边的类的实例,返回boo ...
- 为已经存在的本地项目添加git,以及从远程仓库拉取代码并切换远程分支
前提:先去gitlab或github网站上创建一个新项目,完毕后记得添加.ignore: 1.打开终端,cd到已存在项目的目录 2.输入以下命令行,初始化一个本地仓库: git init 3 ...