前面已經分析把物理內存添加到memblock以及給物理內存建立頁表映射,這裏我們分析內存模型。在Linux內核中支持3種內存模型,分別爲
- flat memory model
- Discontiguous memory model
- sparse memory model
所謂memory model,其實就是從cpu的角度看,其物理內存的分佈情況,在linux kernel中,使用什麼的方式來管理這些物理內存。某些體系架構支持多種內存模型,但在內核編譯構建時只能選擇使用一種內存模型。
1. 基本概念
1.1 page frame
從虛擬地址到物理地址的映射過程,系統對於內存管理是以頁爲單位進行管理的。在linux操作系統中,物理內存是按照page size來管理的,具體page size是多少是和硬件以及linux系統配置相關的,4k是最經典的設定。因此,對於物理內存,我們將其分成一個個按page size排列的page,每一個物理內存中的page size的內存區域我們稱之page frame。page frame是系統內存的最小單位,對內存中的每個頁都會創建struct page實例。
1.2 PFN
對於一個計算機系統,其整個物理地址空間應該是從0開始,到實際系統能支持的最大物理空間爲止的一段地址空間。在ARM系統中,假設物理地址是32個bit,那麼其物理地址空間就是4G,在ARM64系統中,如果支持的物理地址bit數目是48個,那麼其物理地址空間就是256T。當然,實際上這麼大的物理地址空間並不是都用於內存,有些也屬於I/O空間(當然,有些cpu arch有自己獨立的io address space)。因此,內存所佔據的物理地址空間應該是一個有限的區間,不可能覆蓋整個物理地址空間。
PFN是page frame number的縮寫,所謂page frame,就是針對物理內存而言的,把物理內存分成一個個固定長度爲page size的區域,並且給每一個page 編號,這個號碼就是PFN。與page frame的轉換關係如下圖所示
1.3 NUMA
在多核的系統設計中內存的架構有兩種類型計算機,分別以不同的方式管理物理內存。
-
UMA計算機(一致內存訪問,uniform memory access):將可用內存以連續方式組織起來,系統中所有的處理器共享一個統一的,一致的物理內存空間,無論從哪個處理器發起訪問,對內存的訪問時間都是一樣快。其架構圖如下圖所示
-
NUMA計算機(非一致內存訪問,non-uniform memory access):系統各個CPU都有本地內存,可支持特別快速的訪問。各個處理器之間通過總線連接起來,以支持對其他CPU的本地內存的訪問,當然比訪問本地內存慢一些。
從圖中可以看出,每個CPU訪問local memory,速度更快,延遲更小。當然,整體的內存構成一個內存池,CPU也能訪問remote memory,相對來說速度更慢,延遲更大。目前對NUMA
的瞭解僅限於此,在內核中會遇到相關的代碼,大概知道屬於什麼範疇就可以了。
2. linux內存模型
Linux提供了三種內存模型(include/asm-generic/memory_model.h
),一般處理器架構支持一種或者多種內存模型,這個在編譯階段就已經確定,比如目前在ARM64中,使用的Sparse Memory Model
。
2.1 FLAT memory model(平坦內存模型)
如果從系統中任意一個CPU的角度來看,當它訪問物理內存的時候,物理地址空間是一個連續的,沒有空洞的地址空間,那麼這種計算機系統的內存模型就是Flat memory。
早期的系統物理內存不大,那個時候Linux使用平坦內存模型(flat memory model)來管理物理內存就足夠有效了。一個page frame用一個struct page結構體表示,整個物理內存可以用一個由所有struct page構成的數組mem_map表示,而經過頁表查找得到的PFN,正好可以用來做這個數組的小標,__pfn_to_page()函數就是專門來完成這個功能的。
#define __pfn_to_page(pfn) (mem_map + ((pfn) - ARCH_PFN_OFFSET))
對於FLATMEM來說,物理內存本身是連續的,如果不連續的話,那麼中間一部分物理地址是沒有對應的物理內存,就會形成一個個洞,這就浪費了mem_map數組本身佔用的內存空間。對於這種模型,其特點如下:
- 內存連續且不存在空隙
- 這種在大多數情況下,應用於UMA系統“Uniform Memory Access”。
- 通過CONFIG_FLATMEM配置
2.2 discontiguous memory model (不連續內存模型)
如果CPU在訪問物理內存的時候,其地址空間是有一些空洞的,是不連續的,那麼這種計算機系統的內存模型就是Discontiguous memory。在什麼情況下物理內存是不連續的呢?當NUMA出現後,爲了有效的管理NUMA模式的物理內存,一種被稱爲不連續內存模型的實現於1999年被引入linux系統中。在這中模型中,NUMA中的每個Node用一個叫做pglist_data的結構體表示。
應對不連續物理內存的問題似乎是解決了,可是現在你給我一個物理page的地址,使用DISCONTIGMEM的話,我怎麼知道這個page是屬於哪個node的呢,PFN中可沒有包含node編號啊。pfn_to_page()之前乾的活多輕鬆啊,就是索引下數組就得到數組元素struct page了,現在PFN和page之間的對應關係不是那麼直接了,pfn_to_page的任務就開始重起來了。
#define __pfn_to_page(pfn) \
({ unsigned long __pfn = (pfn); \
unsigned long __nid = arch_pfn_to_nid(__pfn); \
NODE_DATA(__nid)->node_mem_map + arch_local_page_offset(__pfn, __nid);\
})
物理內存存在空洞,隨着Sparse Memory
的提出,這種內存模型也逐漸被棄用了。這種內存模型有以下的特點
- 多個內存節點不連續並且存在空隙"hole"
- 適用於UMA系統和NUMA系統
- ARM在2010年已經移除了對DISCONTIGMEM的支持
- 通過CONFIG_CONTIGMEM配置
2.3 sparse memory model(稀疏內存模型)
內存模型是一個逐漸演化的過程,剛開始的時候,由於內存比較小,使用flat memory模型去抽象一個連續的內存地址空間。但是出現了NUMA架構之後,整個不連續的內存空間被分配成若干個node,每個node上是連續的內存地址空間,爲了有效的管理NUMA模型下的物理內存,就開始使用discontiguous memory model。爲了解決DISCONTIGMEM存在的弊端,一種新的稀疏內存模型被使用出來。
在sparse memory內存模型下,連續的地址空間按照SECTION被分成一段一段的,其中每一個section都是Hotplug的,因此sparse memory下,內存地址空間可以被切分的更細,支持更離散的Discontiguous memory。在SPARSEMEM中,被管理的物理內存由一個個任意大小的section(struct mem_section表示)構成,因此整個物理內存可被視爲一個mem_section數組。每個mem_section包含了一個間接指向struct page數組的指針。
其主要的特點如下:
- 多個內存區域不連續並且存在空隙
- 支持內存熱插拔(hot plug memory),但性能稍遜色於DISCONTIGMEM
- 在x86或ARM64內存採用該中模型,其性能比DISCONTIGMEM更優並且與FLATMEM相當
- 對於ARM64平臺默認選擇該內存模型
- 以section爲單位管理online和hot-plug內存
- 通過CONFIG_SPARSEMEM配置
section大小從幾十MiB到幾GiB不等,取決於體系架構和內核的配置。通常在系統配置中將內存擴展單元「memory expansion unit」用作section大小。比如,如果系統內存可擴展至64GiB,並且最小內存擴展單元爲1GiB,則設置section大小也爲1GiB。當使用Linux系統作爲hypervisor的客戶操作系統「guest OS」,也是以section大小爲單元在運行時向Linux系統增添內存和移除Linux系統的內存。
3. 平臺內存模型支持
Linux支持的各種不同體系結構在內存管理方面差別很大,以下是主流的架構支持情況如下表所示,一個體系架構中可能有多種內存模型可用(ARM64只支持一種內存模型),通過可選的內核配置選項來決定使用哪種內存模型。
系統架構 | FLATMEM | DISCONTIGMEM | SPARSEMEM |
---|---|---|---|
ARM | 默認 | 不支持 | 某些系統可選配置 |
ARM64 | 不支持 | 不支持 | 默認 |
x86_32 | 默認 | 不支持 | 可配置 |
x86_32(NUMA) | 不支持 | 默認 | 可配置 |
x86_64 | 不支持 | 不支持 | 默認 |
x86_64(NUMA) | 不支持 | 不支持 | 默認 |
4.小結
這章我們學習了3種內核模型的各自原理和特點,同時我們簡單介紹linux kernel,對於這三種模型使用什麼樣的方式來管理這些物理內存,後面的章節中會針對FLAT(ARM)和SPARSE(ARM64)模型做相應的介紹。