一、為什么需要“大塊內(nèi)核內(nèi)存”?
先明確場景,避免盲目選擇分配方式:
1.DMA傳輸場景:網(wǎng)卡、硬盤等外設(shè)的DMA控制器,要求內(nèi)存物理地址連續(xù)(無法識別虛擬地址映射),且需一次性分配大尺寸緩沖區(qū)(如1GB網(wǎng)絡(luò)幀緩存)。
2.大型內(nèi)核緩存:文件系統(tǒng)(如EXT4)的索引緩存、數(shù)據(jù)庫內(nèi)核的內(nèi)存池,需要持續(xù)占用GB級內(nèi)存,且需虛擬地址連續(xù)(方便指針遍歷)。
3.虛擬化場景:KVM虛擬機(jī)的內(nèi)存分配、容器運(yùn)行時的共享內(nèi)存,需為Guest OS分配大塊連續(xù)內(nèi)存,保障運(yùn)行性能。
4.高性能設(shè)備驅(qū)動:FPGA、GPU等加速卡的驅(qū)動程序,需分配大塊內(nèi)存用于數(shù)據(jù)批量傳輸,減少IO次數(shù)。
二、3種核心申請方法(附實操代碼)
Linux內(nèi)核提供3種大塊內(nèi)存分配接口,核心差異在于“物理連續(xù)與否”和“性能開銷”,需按需選擇:
1. alloc_pages ():物理連續(xù),DMA首選
?核心特點:分配2^order頁的物理連續(xù)內(nèi)存,返回struct page指針(需手動轉(zhuǎn)換為虛擬地址),適合DMA、高性能IO等場景。
?關(guān)鍵參數(shù):
?gfp_mask:分配標(biāo)志(如GFP_KERNEL允許睡眠,GFP_ATOMIC不睡眠);
?order:分配階數(shù)(order=0→1頁,order=1→2頁,…,order=10→1GB,最大order由內(nèi)核配置MAX_ORDER決定,默認(rèn)11→2GB)。
?示例代碼:
// 分配1GB物理連續(xù)內(nèi)存(order=10,假設(shè)PAGE_SIZE=4KB)structpage*page =alloc_pages(GFP_KERNEL | __GFP_ZERO,10);if(!page) {pr_err("alloc_pages failedn");return-ENOMEM;}// 轉(zhuǎn)換為虛擬地址(內(nèi)核虛擬地址=物理地址+PAGE_OFFSET)void*virt_addr =page_address(page);// 釋放內(nèi)存(必須與alloc_pages配對)__free_pages(page,10);
2. __get_free_pages ():alloc_pages封裝,簡化使用
?核心特點:alloc_pages的封裝接口,直接返回虛擬地址(無需手動轉(zhuǎn)換struct page),功能與alloc_pages完全一致,物理連續(xù)。
?示例代碼:
// 分配512MB物理連續(xù)內(nèi)存(order=9,4KB*512=2GB?不:order=9→512頁=2GB?哦,4KB*512=2MB?糾正:4KB*2^9=4KB*512=2048KB=2MB;order=19才是2GB,需注意order計算)void*virt_addr = (void*)__get_free_pages(GFP_KERNEL | __GFP_ZERO,9);if(!virt_addr) {pr_err("__get_free_pages failedn");return-ENOMEM;}// 釋放內(nèi)存(與free_pages配對)free_pages((unsignedlong)virt_addr,9);
?注意:__get_free_pages是宏定義,本質(zhì)調(diào)用alloc_pages,僅簡化地址轉(zhuǎn)換。
3. vmalloc ():虛擬連續(xù),物理離散
?核心特點:分配虛擬地址連續(xù)、物理地址離散的大塊內(nèi)存,通過內(nèi)核頁表映射實現(xiàn),適合對物理連續(xù)性無要求、但需大尺寸內(nèi)存的場景(如內(nèi)核緩存、低訪問頻率緩沖區(qū))。
?優(yōu)勢:支持更大尺寸(理論無上限,受內(nèi)核虛擬地址空間限制),分配成功率高于物理連續(xù)方式。
?劣勢:訪問需經(jīng)過頁表轉(zhuǎn)換,性能比alloc_pages低(延遲高~20%),且不支持DMA。
?示例代碼:
// 分配2GB虛擬連續(xù)內(nèi)存void*virt_addr =vmalloc(2*1024*1024*1024);if(!virt_addr) {pr_err("vmalloc failedn");return-ENOMEM;}// 可選:初始化內(nèi)存(vmalloc不默認(rèn)清零)memset(virt_addr,0,2*1024*1024*1024);// 釋放內(nèi)存(必須用vfree,不能用kfree)vfree(virt_addr);
三、關(guān)鍵注意事項(避坑核心)
1.物理連續(xù)內(nèi)存“稀缺性”:
?order越大,分配成功率越低(系統(tǒng)運(yùn)行越久,物理內(nèi)存越碎片化),建議盡量降低order(如拆分大內(nèi)存為多個小order分配)。
?避免在中斷上下文申請物理連續(xù)大塊內(nèi)存(GFP_ATOMIC不允許睡眠,無法等待內(nèi)存碎片整理)。
1.申請失敗必須處理:
?大塊內(nèi)存分配失敗是常態(tài)(尤其物理連續(xù)方式),需返回錯誤碼或降級處理(如改用vmalloc),不可直接使用NULL指針。
1.釋放接口必須配對:
|
申請接口
|
釋放接口
|
錯誤用法
|
|
alloc_pages()
|
__free_pages()
|
用vfree ()釋放
|
|
__get_free_pages()
|
free_pages()
|
用kfree ()釋放
|
|
vmalloc()
|
vfree()
|
用free_pages ()釋放
|
1.性能與場景匹配:
?高頻訪問的大塊內(nèi)存(如DMA傳輸)用alloc_pages(物理連續(xù),無頁表轉(zhuǎn)換開銷);
?低頻訪問的大內(nèi)存(如內(nèi)核日志緩存)用vmalloc(分配成功率高,不浪費物理連續(xù)內(nèi)存)。
1.NUMA架構(gòu)優(yōu)化:
?多CPU節(jié)點服務(wù)器中,用alloc_pages_node(nid, gfp_mask, order)指定節(jié)點分配,避免跨節(jié)點訪問(跨節(jié)點延遲是本地的2-3倍)。
1.內(nèi)存泄漏風(fēng)險:
?內(nèi)核內(nèi)存無GC機(jī)制,申請后必須在模塊卸載、設(shè)備注銷時釋放,建議用devres機(jī)制(如devm_alloc_pages)自動釋放,減少泄漏風(fēng)險。
四、申請流程可視化(流程圖)

五、知識腦圖(快速梳理)
?-
內(nèi)核
+關(guān)注
關(guān)注
4文章
1468瀏覽量
42888 -
Linux
+關(guān)注
關(guān)注
88文章
11763瀏覽量
219083 -
內(nèi)存
+關(guān)注
關(guān)注
9文章
3211瀏覽量
76380
發(fā)布評論請先 登錄
Linux內(nèi)核內(nèi)存泄漏怎么辦
Linux內(nèi)存相關(guān)知識科普
Linux內(nèi)核內(nèi)存規(guī)整總結(jié)
Linux內(nèi)核內(nèi)存管理架構(gòu)解析
Linux內(nèi)核地址映射模型與Linux內(nèi)核高端內(nèi)存詳解
全流程場景落地 在線測長儀多方位部署 滿足各種檢測需求
Linux內(nèi)存系統(tǒng): Linux 內(nèi)存分配算法
Linux內(nèi)存系統(tǒng):內(nèi)存使用場景
Linux內(nèi)核的相關(guān)資料推薦
LINUX內(nèi)核中的內(nèi)存是如何進(jìn)行分配的
一文解析Linux內(nèi)存系統(tǒng)
Linux內(nèi)核中用GFP_ATOMIC申請內(nèi)存意味著什么
Linux內(nèi)核源碼分析-進(jìn)程的哪些內(nèi)存類型容易引起內(nèi)存泄漏?
Linux內(nèi)核伙伴系統(tǒng)內(nèi)存申請函數(shù)詳解:從原理到實戰(zhàn)
Linux內(nèi)核大塊內(nèi)存申請:從場景到落地全解析
評論