計算機學(xué)習微信公眾號(jsj_xx)
內存管理是操作系統核心功能,盡管有點(diǎn)老(過(guò)時(shí)),我們還是以經(jīng)典的32位x86為例(之后會(huì )分析x86_64),看看linux內核的內存管理。參考linux kernel source code 4.0,為之后分析x86_64版本的內存管理做熱身(如有錯誤,還望指正,謝謝)!
1 內存區劃分
有三種類(lèi)型內存區(假設物理內存大于896M):
ZONE_DMA(0到16M)
ZONE_NORMAL(16M到896M)
ZONE_HIGHMEM(大于896M)
其中,ZONE_DMA和ZONE_NORMAL稱(chēng)為低端內存,ZONE_HIGHMEM稱(chēng)為高端內存(后面會(huì )詳述高端內存)。
2 內存的申請使用
有三種申請函數:
alloc_pages()支持高端內存,返回page指針。
__get_free_pages()僅支持低端內存,返回內核線(xiàn)性地址(內核邏輯地址)。
kmalloc()支持低端內存的字節粒度,實(shí)質(zhì)是調用了__get_free_pages()。
在申請時(shí),有三種標志(屬性):
動(dòng)作屬性
__GFP_WAIT之類(lèi)的。
區類(lèi)型屬性
__GFP_DMA則僅從ZONE_DMA區申請,__GFP_HIGHMEM則從ZONE_HIGHMEM或ZONE_NORMAL申請。此標志位空表示從ZONE_NORMAL或ZONE_DMA申請。
第三種屬性是前兩種的組合而已。
我們關(guān)注一下kmalloc():
如果有GFP_KERNEL,則由于可能睡眠,只能用戶(hù)進(jìn)程上下文。
如果有GFP_ATOMIC,則可以用于中斷或軟中斷場(chǎng)景。
如果有GFP_DMA,則只能從ZONE_DMA申請,一般用于設備驅動(dòng)。
3 高端內存
32bit x86的內存管理中,很重要的就是高端內存的概念,我們詳細討論一下。
3.1 高端內存基礎
首先要明確,使用高端內存由于會(huì )構建頁(yè)表所以會(huì )損失些效率。用到高端內存的時(shí)機:
alloc_pages(GFP_HIGHUSER)
vmalloc()->alloc_pages(GFP_HIGUSER)
內核一般不用高端內存,除非裝載模塊時(shí)可能會(huì )用到vmalloc()。
高端內存又分三種:
固定
kmap()完成,PKMAP_BASE到FIXADDR_START的4M,數量有限,故可能睡眠,一般用在進(jìn)程上下文。
臨時(shí)
kmap_atomic()完成,從FIXADDR_START到FIXADDR_TOP,屬于預留性質(zhì),不會(huì )導致睡眠。注意,臨時(shí)映射需要禁本地cpu中斷,因為預留是根據cpu劃分,不容切換。
非連續
一般場(chǎng)景是,從VMALLOC_START到VMALLOC_END,同時(shí)申請物理內存和線(xiàn)性地址。
注意,這里只是高端映射,有可能映射到低端內存。
直白地理解,就是:內核用1G空間管理4G空間,自然不夠,所以從中留128M做動(dòng)態(tài)反復使用。
3.2 結合源碼理解高端內存
下面,我們結合源碼(linux kernel souce code 4.0)看看。
以下參考find_low_pfn_range():

將實(shí)際物理內存以896M為界,分別處理。
先說(shuō)大于896M的場(chǎng)景,此時(shí)896M和實(shí)際物理內存之間的就屬于高端內存。不管是否打開(kāi)CONFIG_HIGHMEM,都會(huì )設置低端內存為896M:(MAXMEM_PFN即896M)
max_low_pfn = MAXMEM_PFN;
但是,如果不打開(kāi)CONFIG_HIGHMEM,就會(huì )無(wú)視高端內存:
max_pfn = MAXMEM_PFN;
這樣,如果內存高于896M,但是不打開(kāi)CONFIG_HIGHMEM,就只能使用896M以?xún)鹊膬却媪?,真是浪費!
需要注意的是,高端內存區間不能容納超過(guò)此范圍的內存空間,否則忽略并報錯:

再看物理內存小于896M的場(chǎng)景,此時(shí)真的沒(méi)有高端內存的概念了么?首先,不管是否打開(kāi)CONFIG_HIGHMEM,都會(huì )設置低端內存為實(shí)際物理內存大?。ㄐ∮?96M的一個(gè)值):
max_low_pfn = max_pfn;
如果沒(méi)打開(kāi)CONFIG_HIGHMEM,確實(shí)沒(méi)有高端內存的事了。但是,如果打開(kāi)CONFIG_HIGHMEM,則在低端內存(max_low_pfn)留出部分空間(假定依然128M),此空間就還是高端內存的概念:

總結就是:
假設實(shí)際物理內存大小為a
如果192M<=a<=896M(低端必須至少64M,所以128M+64M=192M),(如果打開(kāi)CONFIG_HIGHMEM)則高端內存為[a-128M,a]
如果a>896M,則高端內存為[896M,a]
注意,此處的高端內存是從物理內存角度說(shuō)的,要與內核虛擬空間的角度(1G空間的128M)分開(kāi)理解。
最后,我們再看看VMALLOC區間:
可見(jiàn),VMALLOC_START其實(shí)就是高端內存地址加上8M的間隔。我的理解:VMALLOC區不是固定從896M開(kāi)始,而是從高端內存開(kāi)始的,VMALLOC_END是固定的,這樣,VMALLOC區間完全可能大于128M(考慮實(shí)際物理內存小于896M且打開(kāi)CONFIG_HIGHMEM的場(chǎng)景下,最大可達1G-64M=960M)!想想,其實(shí)很好理解,VMALLOC區間誕生的背景是物理內存遠大于內核空間,而如果內核空間遠大于物理內存呢?
4 總結
就x86 32bit版來(lái)說(shuō),主要是要搞清高端內存的含義,需要從物理內存角度和內核虛擬空間角度兩個(gè)角度去結合理解。其存在的意義,就是為了將更大的內存映射進(jìn)內核空間!下次分析64bit版本(相當于,64T取代896M),因為32bit版本已經(jīng)老去。。。
聯(lián)系客服