Linux内存管理之初始化

= 801

《深入理解linux内核》中对内存管理的解读比较粗略,相比之下陈莉君的书要详细很多了。如果有人想了解内存管理的细节,可以去看看陈莉君的书,确实非常的详细。

简单的记笔记没有什么意思,按自己的疑惑来记录吧!首先,内存管理是对全局内存进行管理的,但是内存管理的数据也需要占内存,又是一个鸡生蛋、蛋生鸡的问题。这个问题和内存页表建立的问题差不多的。先不谈页表吧!页表建立是在内存管理以后的。首先知道一个东西,内存管理的一部分数据是在内核数据段或者初始段的。

        怎么看呢?有一个System.map的文件,这是编译内核之后得到的内核符号表,这张表里面有内核重要的全局数据结构,当然很多很多的函数。以前看到过这个文件,但是没有仔细研究。一看才知道这个文件非常的有用,它里面记录了内核代码区、数据区、初始化区的布局图,变量及函数的地址也尽在其中。由于内核代码太过庞大,反汇编实在不是一个可行的办法。这样System.map就有了大作用。

c0923510 D contig_page_data     //在data段  
co16d598 T bootmem_node_data    //在init段  
c094ae38 B mem_map              //在数据段  

这个文件有4万多行,我截取几个和内存管理有关的看看。上面这几个变量就是内存初始化过程中比较重要的几个变量。这几个重要的数据结构都存在于内核的映像中,这本来应该是很明显的。但是这样一看,感觉心里更有底了。这个鸡和蛋的问题也就有了一点眉目。既然这几个数据都在内核映像里面,内存管理的时候,我们只需要将内核映像区标记为已用,其他的事情就不需要管了。这样就下面就对这几个变量进行分析。

这几个变量在内核中的定义如下:

/*mm/bootmem.c*/  
struct pglist_data __refdata contig_page_data = {  
    .bdata = &bootmem_node_data[0]  
};  
bootmem_data_t bootmem_node_data[MAX_NUMNODES] __initdata; 

 

bootmem_data_t类型的定义如下:

typedef struct bootmem_data {  
        unsigned long node_min_pfn;  
        unsigned long node_low_pfn;  
        void *node_bootmem_map;  
        unsigned long last_end_off;  
        unsigned long hint_idx;  
        struct list_head list;  
} bootmem_data_t;  

为了对页面管理机制作出初步准备,Linux 使用了一种叫 bootmem 分配器(Bootmem Allocator)的机制,这种机制仅仅用在系统引导时,它为整个物理内存建立起一个页面位图。这个位图建立在从 start_pfn 开始的地方,也就是说,内核映像终点_end 上方的地方。这个位图用来管理低区(例如小于 896MB),因为在 0 到 896MB 的范围内,有些页面可能保留,有些页面可能有空洞,因此,建立这个位图的目的就是要搞清楚哪一些物理页面是可以动态分配的。bootmem_data_t结构体中的node_bootmem_map就是一个指向位图的指针。node_boot_start 表示存放 bootmem 位图的第一个页面(即内核映像结束处的第一个页面)。 node_low_pfn 表示物理内存的顶点,最高不超过896MB。

变量 contig_page_data的类型就是前面介绍过的 pg_data_t 数据结构。每个 pg_data_t数据结构代表着一片均匀的、连续的内存空间。在连续空间 UMA 结构中,只有一个节点contig_page_data,而在NUMA 结构或不连续空间 UMA 结构中,有多个这样的数据结构。pg_data_t 结构中有个指针 bdata,bdata 被初始化为指向 bootmem_data_t。

pg_data_t类型的定义如下:

typedef struct pglist_data {   
     zone_t node_zones[MAX_NR_ZONES];   
     zonelist_t node_zonelists[GFP_ZONEMASK+1];   
     int nr_zones;   
     struct page *node_mem_map;   
     unsigned long *valid_addr_bitmap;   
     struct bootmem_data *bdata;   
     unsigned long node_start_paddr;   
     unsigned long node_start_mapnr;   
     unsigned long node_size;   
     int node_id;   
     struct pglist_data *node_next;   
} pg_data_t;   

每个结构中的 node_mem_map 指向具体节点的 page 结构数组。另外一个重要的变量就是剩下的mem_page。变量 mem_map 是类型为 struct pages 的全局稀疏矩阵。我们应该知道每一个内存页面都有一个page变量对应它。pg_data_t中的node_mem_map变量也是一个page数组,但是它只是全局矩阵mem_page的一部分。因为Linux要支持NUMA结构。最后一张图结束吧!

20140903002015444

发表评论