SLIT 表則記錄了各個結點之間的距離,在系統中由數組 node_distance[ ] 記錄。


    Linux 采用 Node、Zone 和頁三級結構來描述物理內存的,如圖 2 所示, 
  
  
  
      圖 2 Linux 中 Node、Zone 和頁的關系
  
  . 1 結點
  
    Linux 用一個 struct pg_data_t 結構來描述系統的內存,系統中每個結點都掛接在一個 pgdat_list 列表中,對 UMA 體系結構,則只有一個靜態(tài)的 pg_data_t 結構 contig_page_data。對 NUMA 系統來說則非常容易擴充,NUMA 系統中一個結點可以對應 Linux 存儲描述中的一個結點,具體描述見 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;


     下面就該結構中的主要域進行說明: 
































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

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














類型 地址范圍
ZONE_DMA 前16MB內存
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;



      下面就該結構中的主要域進行說明: 






































說明
Lock 旋轉鎖,用于保護該zone
free_pages 該zone空閑頁總數
pages_min,

pages_low,


pages_high

Zone的閾值
need_balance 該標志告訴kswapd需要對該zone的頁進行交換
Free_area 空閑區(qū)域的位圖,用于buddy分配器
wait_table 等待釋放該頁進程的隊列散列表,這對wait_on_page()和unlock_page()是非常重要的。當進程都在一條隊列上等待時,將引起進程的抖動
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的大小,以頁為單位

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