Hi,guys 1. Linux对Memory的认知。 Linux采用NUMA(Non-Uniform Memory Access)组织物理内存。根据CPU访问内存的"距离"("distance"),将内存分为不同的bank,每一个bank称为一个node,每一个node通过数据结构pg_data_t描述,所有的nodes通过pgdat_list全局链表链接,具体的划分机制和平台相关。由于我只有I386体系的机子,因此,我们现在只考虑I386体系。I386认知所有物理内存为一个node,记为contig_page_data,故而pgdat_list链表也只有contig_page_data一个结点。因此,我们可以认为I386体系其实质是采用的UMA机制。我认为Linux采用NUMA机制的目的是最大限度地提高代码的可扩展性和平台间可移植性。 对于一个node,Linux最多可以将其分成3个域(zone):ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM。在I386体系中:ZONE_DMA负责最开始16MB;ZONE_NORMAL负责16MB~896MB(内核可以直接访问的物理空间);ZONE_HIGHMEM负责896MB以后的空间(内核不能直接访问的物理空间)。每个域是通过数据结构zone_t描述。而具体的内存页面是通过数据结构page描述的。 1.1 区域水位 每个zone都有三个水位,当前自由页面数目与这三个水位值比较,决定pageout守护进程kswapd的操作: pages_min: 当自由页面数目小于等于pages_min时,kswapd必须以同步模式工作,申请页面的进程必须sleep直到自由页面数目超过pages_min。 pages_low: 当自由页面数目小于等于pages_low时,kswapd进程被唤醒,通过buddy分配器释放页面,以增加自由页面数目;pages_low缺省是pages_min的两倍。 pages_high:当自由页面数目大于等于pages_high时,kswapd不会被唤醒,系统认为zone是平稳、安定的(balanced)。 Pfree小于pages_min,大于pages_high都好理解。其它的情况,我的理解是: 假设Pfree属于(pages_min, pages_low): kswapd是可以唤醒的,并通过buddy分配器释放页面;假设Pfree属于(pages_low, pages_high): 系统认为该zone不是"balanced",需要kswapd调整平衡值。 1.2 Linux支持的最大区域 <mm/page_alloc.c> zone_t *zone_table[MAX_NR_ZONES*MAX_NR_NODES]; 系统能支持的最大zone数目是MAX_NR_ZONES(一个node支持的最大zone数目)乘以MAX_NR_NODES(系统支持的最大node数目),zone_table是存放系统区域结构地址指针数组的首地址。 建立页面和区域之间的联系: <include/linux/mm.h> static inline void set_page_zone(struct page *page, unsigned long zone_num) { page->flags &= ~(~0UL << ZONE_SHIFT); page->flags |= zone_num << ZONE_SHIFT; } 2. 页表管理 Linux采用了与平台无关性的三级页表管理(PGD-PMD-PTE-Offset),如果硬件平台只支持两级页面管理(没有使用PAE机制的I386体系),Linux只是将PMD设置为1,其实质是两级页面管理了。 2.1 I386页表类型定义 <include/asm-i386/page.h> #if CONFIG_X86_PAE typedef struct { unsigned long pte_low, pte_high; } pte_t; typedef struct { unsigned long long pmd; } pmd_t; typedef struct { unsigned long long pgd; } pgd_t; #define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32)) #else typedef struct { unsigned long pte_low; } pte_t; typedef struct { unsigned long pmd; } pmd_t; typedef struct { unsigned long pgd; } pgd_t; #define pte_val(x) ((x).pte_low) #endif 这段定义,我们需要注意的是PAE模式下pte_t的定义:pte_high指向36位地址线的高4位。 typedef struct { unsigned long pgprot; } pgprot_t; pgprot_t用于表示存储页面属性,每一个页面属性存储在pte_t的低12位里。具体属性类型定义在include/asm-i386/pgtable.h中。比如: #define _PAGE_USER 0x004 static inline int pte_read(pte_t pte) { return (pte).pte_low & _PAGE_USER; } waiting......... Best Regards Ouyang Kai