前面說了,Linux MM系統細節非常多,自己在探究的時候,也是嘗試盡量抓住主線,這裡也只能抽取了一些“主線劇情”介紹,其中還可以擴充出很多細節,看客感興趣可以自己深究,後續如果興趣還在,我也還會繼續寫出來。核心版本如果沒有特別說明,就是使用2.6.33版本。
1. 實體記憶體組織
先聲明一下,這裡說的Linux都是運行Intel X86架構的。從80386開始,為了更好支援記憶體管理、虛擬記憶體技術,x86架構開始支援處理器的分頁模式(分頁是基於分段)。系統將記憶體分為一個個固定大小的塊,稱作“page frames”,x86架構每一個“page frames”大小為4096位元組。Linux中使用struct page結構來描述一個“page frames”【連結中給出了2.6.18核心下的Page結構】,一個Page結構對應了一個實體記憶體頁。
在Linux中,所有的struct page對象都放在一個數組mem_map,mem_map每一個元素對應一個Page。
2. NUMA下的記憶體結構
在NUMA架構下,系統根據CPU的物理顆數,將記憶體分成對應的Node。例如,兩顆物理CPU,16GB記憶體的硬體:系統則將記憶體分成兩個8GB,分別分配給兩顆CPU:
my111.cm3:/root>#numactl --hardware
available: 2 nodes (0-1)
node 0 size: 8065 MB
node 1 size: 8080 MB
每一個Node,系統又將其分為多個Zone,
64位x86架構下(參考:8.1.5),分為兩個ZONE_DMA(低16MB,)、ZONE_NORMAL(其餘記憶體)。所以NUMA架構下的記憶體配置,也就是在各個zone分配記憶體。
3. 記憶體配置函數棧
從底層系統的角度,記憶體配置有如下函數(這裡介紹的底層函數,和上層函數的關係,以後再介紹):
這裡來調查一下函數alloc_pages都做了些什麼,都調用了哪些函數:
free_area是一個底層儲存空閑記憶體頁的數組,有著特殊的結構,它也是記憶體配置Buddy system的核心變數。
4. get_page_from_freelist和zone_reclaim_mode
上面函數get_page_from_freelist【mm/page_alloc.c】通過遍曆系統中各個zone,來尋找可用記憶體,根據Linux系統中zone_reclaim_mode的設定不同,遍曆時的行為略有不同。zone_reclaim_mode是Linux中的一個可配置參數,為瞭解該參數如何影響記憶體配置,那就開啟get_page_from_freelist的代碼,仔細看看遍曆各個zone的流程:
上面看到,zone_reclaim_mode非零時,如果某個zone記憶體不夠,則會嘗試出發一次記憶體回收工作(zone_reclaim),等於零時,則直接嘗試寫一個zone。
上面是2.6.33核心的代碼流程圖,2.6.18(RHEL5.4的核心)中則因為沒有zcl相對簡單一些:
流程圖中可以看到,zone_reclaim_mode非零時,get_page_from_freelist【mm/page_alloc.c】函數中會調用zone_watermark_ok掃描free_area,如果當面有沒有足夠的可用記憶體,就會調用zone_reclaim【mm/vmscan.c】函數回收記憶體,zone_reclaim實際調用zone_reclaim【mm/vmscan.】收回記憶體。
最後
每次深入瞭解一個技術問題,隨著挖據的深入,都發現其背後總非常深的背景知識,甚至需要深入到很多底層系統,這個過程有時會讓自己迷失,會讓自己忘了當初的目的。如果是Linux方面的技術問題,一般最後會收縮到“體繫結構”、“Linux原理”和“演算法”,這恰恰對應了電腦系考研時候的三門課程:體繫結構、作業系統、和資料結構