linux mmu的实现的讲解_Linux中的物理内存管理 [一]
前面的文章介紹了Linux中虛擬地址空間的管理,本文將討論Linux系統對物理內存的管理。
NUMA
所謂物理內存,就是安裝在機器上的,實打實的內存設備(不包括硬件cache),被CPU通過總線訪問。在多核系統中,如果物理內存對所有CPU來說沒有區別,每個CPU訪問內存的方式也一樣,則這種體系結構被稱為Uniform Memory Access(UMA)。
如果物理內存是分布式的,由多個cell組成(比如每個核有自己的本地內存),那么CPU在訪問靠近它的本地內存的時候就比較快,訪問其他CPU的內存或者全局內存的時候就比較慢,這種體系結構被稱為Non-Uniform Memory Access(NUMA)。
以上是硬件層面上的NUMA,而作為軟件層面的Linux,則對NUMA的概念進行了抽象。即便硬件上是一整塊連續內存的UMA,Linux也可將其劃分為若干的node。同樣,即便硬件上是物理內存不連續的NUMA,Linux也可將其視作UMA。
所以,在Linux系統中,你可以基于一個UMA的平臺測試NUMA上的應用特性。從另一個角度,UMA就是只有一個node的特殊NUMA,所以兩者可以統一用NUMA模型表示。
在NUMA系統中,當Linux內核收到內存分配的請求時,它會優先從發出請求的CPU本地或鄰近的內存node中尋找空閑內存,這種方式被稱作local allocation,local allocation能讓接下來的內存訪問相對底層的物理資源是local的。
每個node由一個或多個zone組成(我們可能經常在各種對虛擬內存和物理內存的描述中迷失,但以后你見到zone,就知道指的是物理內存),每個zone又由若干page frames組成(一般page frame都是指物理頁面)。
Page Frame
雖然內存訪問的最小單位是byte或者word,但MMU是以page為單位來查找頁表的,page也就成了Linux中內存管理的重要單位。包括換出(swap out)、回收(relcaim)、映射等操作,都是以page為粒度的。
因此,描述page frame的struct page自然成為了內核中一個使用頻率極高,非常重要的結構體,來看下它是怎樣構成的(為了講解需要并非最新內核代碼):
struct page {unsigned long flags;atomic_t count; atomic_t _mapcount; struct list_head lru;struct address_space *mapping;unsigned long index; ... }- flags表示page frame的狀態或者屬性,包括和內存回收相關的PG_active, PG_dirty, PG_writeback, PG_reserved, PG_locked, PG_highmem等。其實flags是身兼多職的,它還有其他用途,這將在下文中介紹到。
- count表示引用計數。當count值為0時,該page frame可被free掉;如果不為0,說明該page正在被某個進程或者內核使用,調用page_count()可獲得count值。
- _mapcount表示該page frame被映射的個數,也就是多少個page table entry中含有這個page frame的PFN。
- lru是"least recently used"的縮寫,根據page frame的活躍程度(使用頻率),一個可回收的page frame要么掛在active_list雙向鏈表上,要么掛在inactive_list雙向鏈表上,以作為頁面回收的選擇依據,lru中包含的就是指向所在鏈表中前后節點的指針(參考這篇文章)。
- 如果一個page是屬于某個文件的(也就是在page cache中),則mapping指向文件inode對應的address_space(這個結構體雖然叫address_space,但并不是進程地址空間里的那個address space),index表示該page在文件內的offset(以page size為單位)。
有了文件的inode和index,當這個page的內容需要和外部disk/flash上對應的部分同步時,才可以找到具體的文件位置。如果一個page是anonymous的,則mapping指向表示swap cache的swapper_space,此時index就是swapper_space內的offset。
事實上,現在最新Linux版本的struct page實現中大量用到了union,也就是同一個元素在不同的場景下有不同的意義。這是因為每個page frame都需要一個struct page來描述,一個page frame占4KB,一個struct page占32字節,那所有的struct page需要消耗的內存占了整個系統內存的32/4096,不到1%的樣子,說小也小,但一個擁有4GB物理內存的系統,光這一項的開銷最大就可達30多MB。
如果能在struct page里省下4個字節,那就能省下4多MB的內存空間,所以這個結構體的設計必須非常考究,不能因為多一種場景的需要就在struct page中增加一個元素,而是應該盡量采取復用的方式。
需要注意的是,struct page描述和管理的是這4KB的物理內存,它并不關注這段內存中的數據變化。
Zone
因為硬件的限制,內核不能對所有的page frames采用同樣的處理方法,因此它將屬性相同的page frames歸到一個zone中。對zone的劃分與硬件相關,對不同的處理器架構是可能不一樣的。
比如在i386中,一些使用DMA的設備只能訪問0~16MB的物理空間,因此將0~16MB劃分為了ZONE_DMA。ZONE_HIGHMEM則是適用于要訪問的物理地址空間大于虛擬地址空間,不能建立直接映射的場景。除開這兩個特殊的zone,物理內存中剩余的部分就是ZONE_NORMAL了。
在其他一些處理器架構中,ZONE_DMA可能是不需要的,
ZONE_HIGHMEM也可能沒有。比如在64位的x64中,因為內核虛擬地址空間足夠大,不再需要ZONE_HIGH映射,但為了區分使用32位地址的DMA應用和使用64位地址的DMA應用,64位系統中設置了ZONE_DMA32和ZONE_DMA。
所以,同樣的ZONE_DMA,對于32位系統和64位系統表達的意義是不同的,ZONE_DMA32則只對64位系統有意義,對32位系統就等同于ZONE_DMA,沒有單獨存在的意義。
此外,還有防止內存碎片化的ZONE_MOVABLE和支持設備熱插拔的ZONE_DEVICE。可通過“cat /proc/zoneinfo |grep Node”命令查看系統中包含的zones的種類。
Zone雖然是用于管理物理內存的,但zone與zone之間并沒有任何的物理分割,它只是Linux為了便于管理進行的一種邏輯意義上的劃分。Zone在Linux中用struct zone表示(以下為了講解需要,調整了結構體中元素的順序):
struct zone {spinlock_t lock;unsigned long spanned_pages;unsigned long present_pages; unsigned long nr_reserved_highatomic; atomic_long_t managed_pages;struct free_area free_area[MAX_ORDER];unsigned long _watermark[NR_WMARK];long lowmem_reserve[MAX_NR_ZONES];atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];unsigned long zone_start_pfn;struct pglist_data *zone_pgdat;struct page *zone_mem_map;... }- lock是用來防止并行訪問struct zone的spin lock,它只能保護struct zone這個結構體哈,可不能保護整個zone里的所有pages。
- spanned_pages是這個zone含有的總的page frames數目。在某些體系結構(比如Sparc)中,zone中可能存在沒有物理頁面的"holes",spanned_pages減去這些holes里的absent pages就是present_pages。
nr_reserved_highatomic是為某些場景預留的內存(參考本系列的第三篇文章),managed_pages是由buddy內存分配系統管理的page frames數目,其實也就是present_pages減去reserved pages。
- free_area由free list空閑鏈表構成,表示zone中還有多少空余可供分配的page frames。_watermark有min(mininum), low, high三種,可作為啟動內存回收的判斷標準(詳情請參考這篇文章)。
lowmem_reserve是給更高位的zones預留的內存(更詳細的介紹請參考這篇文章)。vm_stat作為zone的內存使用情況的統計信息,是“/proc/zoneinfo”的數據來源。
- zone_start_pfn是zone的起始物理頁面號,zone_start_pfn+spanned_pages就是該zone的結束物理頁面號。zone_pgdat是指向這個zone所屬的node的。zone_mem_map指向由struct page構成的mem_map數組。
因為內核對zone的訪問是很頻繁的,為了更好的利用硬件cache來提高訪問速度,struct zone中還有一些填充位,用于幫助結構體元素的cache line對齊。這和struct page對內存精打細算的使用形成了鮮明的對比,因為zone的種類很有限,一個系統中一共也不會有多少個zones,struct zone這個結構體的體積大點也沒有什么關系。
關于前面提到的node的介紹,請看下文分解。
原創文章,轉載請注明出處。
總結
以上是生活随笔為你收集整理的linux mmu的实现的讲解_Linux中的物理内存管理 [一]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c语言股票最大收益_金斧子股票配资:股票
- 下一篇: python 高斯烟羽模型_GPR(高斯