看到了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. 基于jQuery个性圆圈倒计时特效

    基于jQuery个性圆圈倒计时特效里面包含十几款不用效果的jQuery倒计时特效下载.效果图如下: 在线预览   源码下载 实现的代码. html代码: <section class=" ...

  2. [转]ssh中如何实现定时任务(spring对quartz的支持)

    原文地址:http://blog.csdn.net/qq_18675693/article/details/50413889 实现定时任务:quartz spring中对quartz进行了封装,使得我 ...

  3. JAVA传入一个字符串,返回一个字符串中的大写字母

    /**      *       * @param 传入一个字符串      * @return 返回一个字符串中的大写字母      */     private static String str ...

  4. am335x SPI spi_d0, spi_d1 out, in 模式设定

    AM335x SPI DO DI 的模式 参考: https://www.deyisupport.com/question_answer/dsp_arm/sitara_arm/f/25/t/13826 ...

  5. PHP——大话PHP设计模式——链式操作

  6. CAS (13) —— CAS 使用Maven Profile支持多环境编译

    CAS (13) -- CAS 使用Maven Profile支持多环境编译 摘要 CAS 使用Maven Profile支持多环境编译 版本 tomcat版本: tomcat-8.0.29 jdk版 ...

  7. WinDbg F9时“code not found breakpoint not set”

    当使用Windbg 6.2.9200.16384 进行源码调试时,无法在代码文件中F9设置断点,会出现“code not found breakpoint not set”,我们只有启动下我们自己的驱 ...

  8. oozie 客户端常用命令

    1.提交作业,作业进入PREP状态 oozie job -oozie http://localhost:11000/oozie -config job.properties -submit job: ...

  9. dapper支持操作函数和事物

    dapper除了支持基础的CURD.存储过程以外,还支持操作函数和事物. dapper操作函数的代码如下: using Dapper; using System; using System.Colle ...

  10. IDEA快捷键笔记

    Keymap:Mac OS X idea快速清除无用的引用:command+alt+o 跳转: 不同窗口之间的跳转(Next project window): alt + command + ] Pr ...