看到了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()的更多相关文章

  1. 内存管理 初始化(八) 至kswapd_init

    至此,内存初始化部分已看完,遗留问题: 1.对于unicore或者mips的页表建立都很清楚,但是对于ARM我不清楚: 初始化部分涉及的页表映射建立,我都以unicore架构为准,ARM的页表映射从原 ...

  2. 垃圾回收GC:.Net自己主动内存管理 上(三)终结器

    垃圾回收GC:.Net自己主动内存管理 上(三)终结器 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己主 ...

  3. 内存管理 初始化(五)kmem_cache_init 初始化slab分配器(上)

    看了下kmem_cache_init,涉及到不同MIGRATE间的buddy system的迁移,kmem_cache的构建,slab分配器头的构建.buddy system的伙伴拆分. 对于SMP系 ...

  4. linux内存管理初始化

    内存管理子系统是linux内核最核心最重要的一部分,内核的其他部分都需要在内存管理子系统的基础上运行.而对其初始化是了解整个内存管理子系统的基础.对相关数据结构的初始化是从全局启动例程start_ke ...

  5. 内存管理 初始化(六)vmalloc_init 及 ioremap

    是不是我错了,本想这个函数会如网上所说将进行非连续内存管理的初始化,但是对于2.6.34的ARM架构而言,该函数实际完成的业务非常少. 内存管理的初始化读到此处,我感觉原有的认识存在很大缺陷: (1) ...

  6. 内存管理初始化源码4:add_active_range

    我们在阅读源码时,函数功能可以分为两类:1. bootmem.c 2. page_alloc.c. 1. bootmem.c是关于bootmem allocator的,上篇文章已经简述过. 2. pa ...

  7. 内存管理初始化源码3:bootmem

    start_kernel ——> setup_arch ——> arch_mem_init ——> bootmem_init ——> init_bootmem_node: 此时 ...

  8. 内存管理初始化源码2:setup_arch

    PFN相关宏说明: /* kernel/include/linux/pfn.h */ PFN : Page Frame Number(物理页帧) /* * PFN_ALIGN:返回地址x所在那一页帧的 ...

  9. 内存管理初始化源码1:setup_arch

    源码声明:基于Linux kernel 3.08 1. 在kernel/arch/mips/kernel/head.S中会做一些特定硬件相关的初始化,然后会调用内核启动函数:start_kernel: ...

随机推荐

  1. list<PageData>传jsp隐藏域,在传回java

    java传jsp,代码如下: /**去修改页面 * @param * @throws Exception */ @RequestMapping(value="/goEdit") p ...

  2. MySQL5.7 添加用户、删除用户与授权

    mysql -uroot -proot MySQL5.7 mysql.user表没有password字段改 authentication_string: 一. 创建用户: 命令:CREATE USER ...

  3. Chrome 插件编写日记

    Chrome 插件,你可以理解为打开了一个网页,但是里面只有前端语言,JavaScript, HTML + css 但是有一点区别的是,它是有一个名字为 manifest.json 的配置文件的,里面 ...

  4. JavaScript 中 类型转换

    转自 https://www.cnblogs.com/wuxiaoshang/p/5835627.html // 转换成字符型 var married = false; alert(married.t ...

  5. 在Linux下用make指令编译进度条程序。

    首先建立一个新的文件,touch progress_bar.c 运行该vim progress_bar.c命令.写进度条的程序. 写进一个进度条程序: #include<stdio.h> ...

  6. web界面设计

    本书描述了6个设计原理,即直截了当.简化交互.足不出户.提供邀请.使用变换.即时反应. 一.直截了当(alan cooper:"在哪里输出,就要允许在哪里输入") 1.1 行内编辑 ...

  7. 【转载】一文总结学习 Python 的 14 张思维导图

    本文主要涵盖了 Python 编程的核心知识(暂不包括标准库及第三方库,后续会发布相应专题的文章). 首先,按顺序依次展示了以下内容的一系列思维导图:基础知识,数据类型(数字,字符串,列表,元组,字典 ...

  8. Android Studio apk 打包

    1.Build -> Generate Signed APK...,打开如下窗口 2.假设这里没有打过apk包,点击Create new,窗口如下 这里只要输入几个必要项 Key store p ...

  9. 关于Unity中红外线瞄准的效果实现

    今天做一个FPS游戏的时候,由于我做的是第三人称的射击,所以需要一个枪的红外线瞄准的效果. 一开始我在枪上挂一个很细很长的聚光灯,瞄准远处物体的时候,看起来有点红外线的样子,但是靠近之后光线就变成一个 ...

  10. 反编译CMD命令

    1.反XML命令 E:\HuaWei Tools\android\apktool-install-windows-r04-brut1 java -jar AXMLPrinter2.jar  guide ...