内存管理 初始化(三)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: ...
随机推荐
- C语言 · 删除重复元素
算法提高 11-2删除重复元素 时间限制:10.0s 内存限制:256.0MB 问题描述 为库设计新函数DelPack,删除输入字符串中所有的重复元素.不连续的重复元素也要删除. 要 ...
- [uEnv.txt]在uEnv.txt文件中使用if语句实现Image/dtb文件切换
指定image/dtb文件 bootdir= bootfile=zImage fdtfile=embest-SBCC_PH8800_WLQ.dtb loadaddr=0x82000000 fdtadd ...
- AT24Cxx(EEPROM)子系统
1.配置内核 打开I2C功能: 打开杂项设备,该选项打开后,EEPROM也就打开了. 2. 修改代码 修改文件: linux/arch/arm/mach-s3c2440/mach-smdk2440.c ...
- Java编程的逻辑 (64) - 常见文件类型处理: 属性文件/CSV/EXCEL/HTML/压缩文件
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...
- Redis源码研究—基础知识
1. Redis 是什么 Redis是一个开源的使用ANSI C语言编写的基于内存的key/value存储系统,与memcache类似,但它支持的value类型更多,包括:字符串(string).链表 ...
- 升级 Elasticsearch 集群数量实战记录
搜索引擎 升级 Elasticsearch 集群数量实战记录 现在线上有一个elasticsearch集群搜索服务有三台elasticsearch实例(es1.es2.es3),打算将其升级为5台(增 ...
- [技术选型] dubbo
分布式服务架构 - 阿里开源项目 简介 Dubbo架构设计详解 Dubbo与Zookeeper.SpringMVC整合和使用(负载均衡.容错)
- TestNG 入门指导——理解testng.xml执行/不执行某个包,某个类,某个方法
这一篇我们主要学习如下几个知识点: ⑴关于testng.xml ⑵创建一个测试套件 ⑶执行testng.xml ⑷在测试套件中创建多个测试用例 ⑸在用例中增加class,packages, metho ...
- 3种启动tornado的方式
r"""A non-blocking, single-threaded HTTP server. 翻译: 一个非阻塞的单线程HTTP服务器 A server is def ...
- Android---如何返回上一Activity
Android 代码用来返回上一个activity 调用onKeyDown()时发生java.lang.NullPointerException. 来自:CSDN博客推荐文章 | 时间:2012 ...