SLIT 表則記錄了各個(gè)結(jié)點(diǎn)之間的距離,在系統(tǒng)中由數(shù)組 node_distance[ ] 記錄。


    Linux 采用 Node、Zone 和頁三級(jí)結(jié)構(gòu)來描述物理內(nèi)存的,如圖 2 所示, 
  
  
  
      圖 2 Linux 中 Node、Zone 和頁的關(guān)系
  
  . 1 結(jié)點(diǎn)
  
    Linux 用一個(gè) struct pg_data_t 結(jié)構(gòu)來描述系統(tǒng)的內(nèi)存,系統(tǒng)中每個(gè)結(jié)點(diǎn)都掛接在一個(gè) pgdat_list 列表中,對(duì) UMA 體系結(jié)構(gòu),則只有一個(gè)靜態(tài)的 pg_data_t 結(jié)構(gòu) contig_page_data。對(duì) NUMA 系統(tǒng)來說則非常容易擴(kuò)充,NUMA 系統(tǒng)中一個(gè)結(jié)點(diǎn)可以對(duì)應(yīng) Linux 存儲(chǔ)描述中的一個(gè)結(jié)點(diǎn),具體描述見 linux/mmzone.h。 




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;


     下面就該結(jié)構(gòu)中的主要域進(jìn)行說明: 
































說明
Node_zones 該結(jié)點(diǎn)的 zone 類型,一般包括 ZONE_HIGHMEM、ZONE_NORMAL 和 ZONE_DMA 三類
Node_zonelists 分配時(shí)內(nèi)存時(shí) zone 的排序。它是由 free_area_init_core() 通過 page_alloc.c 中的 build_zonelists() 設(shè)置 zone 的順序
nr_zones 該結(jié)點(diǎn)的 zone 個(gè)數(shù),可以從 1 到 3,但并不是所有的結(jié)點(diǎn)都需要有 3 個(gè) zone
node_mem_map 它是 struct page 數(shù)組的第一頁,該數(shù)組表示結(jié)點(diǎn)中的每個(gè)物理頁框。根據(jù)該結(jié)點(diǎn)在系統(tǒng)中的順序,它可在全局 mem_map 數(shù)組中的某個(gè)位置
Valid_addr_bitmap 用于描述結(jié)點(diǎn)內(nèi)存空洞的位圖
node_start_paddr 該結(jié)點(diǎn)的起始物理地址
node_start_mapnr 給出在全局 mem_map 中的頁偏移,在free_area_init_core() 計(jì)算在 mem_map 和 lmem_map 之間的該結(jié)點(diǎn)的頁框數(shù)目
node_size 該 zone 內(nèi)的頁框總數(shù)
node_id 該結(jié)點(diǎn)的 ID,全系統(tǒng)結(jié)點(diǎn) ID 從 0 開始

    系統(tǒng)中所有結(jié)點(diǎn)都維護(hù)在 pgdat_list 列表中,在 init_bootmem_core 函數(shù)中完成該列表初始化工作。 
  
     2.2 Zone
  
    每個(gè)結(jié)點(diǎn)的內(nèi)存被分為多個(gè)塊,稱為zones,它表示內(nèi)存中一段區(qū)域。一個(gè)zone用struct_zone_t結(jié)構(gòu)描述,zone的類型主要有ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM。ZONE_DMA位于低端的內(nèi)存空間,用于某些舊的ISA設(shè)備。ZONE_NORMAL的內(nèi)存直接映射到Linux內(nèi)核線性地址空間的高端部分,許多內(nèi)核操作只能在ZONE_NORMAL中進(jìn)行。例如,在X86中,zone的物理地址如下:   














類型 地址范圍
ZONE_DMA 前16MB內(nèi)存
ZONE_NORMAL 16MB – 896MB
ZONE_HIGHMEM 896 MB以上


  
    Zone是用struct zone_t描述的,它跟蹤頁框使用、空閑區(qū)域和鎖等信息,具體描述如下:




typedef struct zone_struct {
spinlock_t lock;
unsigned long free_pages;
unsigned long pages_min, pages_low, pages_high;
int need_balance;
free_area_t free_area[MAX_ORDER];
wait_queue_head_t * wait_table;
unsigned long wait_table_size;
unsigned long wait_table_shift;
struct pglist_data *zone_pgdat;
struct page *zone_mem_map;
unsigned long zone_start_paddr;
unsigned long zone_start_mapnr;
char *name;
unsigned long size;
} zone_t;



      下面就該結(jié)構(gòu)中的主要域進(jìn)行說明: 






































說明
Lock 旋轉(zhuǎn)鎖,用于保護(hù)該zone
free_pages 該zone空閑頁總數(shù)
pages_min,

pages_low,


pages_high

Zone的閾值
need_balance 該標(biāo)志告訴kswapd需要對(duì)該zone的頁進(jìn)行交換
Free_area 空閑區(qū)域的位圖,用于buddy分配器
wait_table 等待釋放該頁進(jìn)程的隊(duì)列散列表,這對(duì)wait_on_page()和unlock_page()是非常重要的。當(dāng)進(jìn)程都在一條隊(duì)列上等待時(shí),將引起進(jìn)程的抖動(dòng)
zone_mem_map 全局mem_map中該zone所引用的第一頁
zone_start_paddr 含義與node_start_paddr類似
zone_start_mapnr 含義與node_start_mapnr類似
Name 該zone的名字。如,“DMA”,“Normal”或“HighMem”
Size Zone的大小,以頁為單位

    當(dāng)系統(tǒng)中可用的內(nèi)存比較少時(shí),kswapd將被喚醒,并進(jìn)行頁交換。如果需要內(nèi)存的壓力非常大,進(jìn)程將同步釋放內(nèi)存。如前面所述,每個(gè)zone有三個(gè)閾值,稱為pages_low,pages_min和pages_high,用于跟蹤該zone的內(nèi)存壓力。pages_min的頁框數(shù)是由內(nèi)存初始化free_area_init_core函數(shù),根據(jù)該zone內(nèi)頁框的比例計(jì)算的,最小值為20頁,最大值一般為255頁。當(dāng)?shù)竭_(dá)pages_min時(shí),分配器將采用同步方式進(jìn)行kswapd的工作;當(dāng)空閑頁的數(shù)目達(dá)到pages_low時(shí),kswapd被buddy分配器喚醒,開始釋放頁;當(dāng)達(dá)到pages_high時(shí),kswapd將被喚醒,此時(shí)kswapd不會(huì)考慮如何平衡該zone,直到有pages_high空閑頁為止。一般情況下,pages_high缺省值是pages_min的3倍。
  
    Linux存儲(chǔ)管理的這種層次式結(jié)構(gòu)可以將ACPI的SRAT和SLIT信息與Node、Zone實(shí)現(xiàn)有效的映射,從而克服了傳統(tǒng)Linux中平坦式結(jié)構(gòu)無法反映NUMA架構(gòu)的缺點(diǎn)。當(dāng)一個(gè)任務(wù)請(qǐng)求分配內(nèi)存時(shí),Linux采用局部結(jié)點(diǎn)分配策略,首先在自己的結(jié)點(diǎn)內(nèi)尋找空閑頁;如果沒有,則到相鄰的結(jié)點(diǎn)中尋找空閑頁;如果還沒有,則到遠(yuǎn)程結(jié)點(diǎn)中尋找空閑頁,從而在操作系統(tǒng)級(jí)優(yōu)化了訪存性能。