核心記憶體分配常用函式使用

發表於2016-11-05

1.kmalloc

kmalloc記憶體分配和malloc相似,除非被阻塞否則他執行的速度非常快,而且不對獲得空間清零.
<
tiger說明:在用kmalloc申請函式後,要對起清零
用memset()函式對申請的記憶體進行清零。
>

kamlloc 函式原型

void *kmalloc(size_t size, int flags);

(1)第一個引數是要分配的塊的大小

(2)第二個引數是分配標誌(flags),他提供了多種kmalloc的行為。

(3)第三個最常用的GFP_KERNEL;

A.表示記憶體分配(最終總是呼叫get_free_pages來實現實際的分配;這就是GFP字首的由來)是代表執行在核心空間的程式執行的。使用GFP_KERNEL容許kmalloc在分配空閒記憶體時候如果記憶體不足容許把當前程式睡眠以等待。因此這時分配函式必須是可重入的。如果在程式上下文之外如:中斷處理程式、tasklet以及核心定時器中這種情況下current程式不該睡眠,驅動程式該使用GFP_ATOMIC.

B.GFP_ATOMIC:用來從中斷處理和程式上下文之外的其他程式碼中分配記憶體. 從不睡眠.

C.GFP_KERNEL:核心記憶體的正常分配. 可能睡眠.

D.GFP_USER:用來為使用者空間頁來分配記憶體; 它可能睡眠.

E.GFP_HIGHUSER:如同 GFP_USER, 但是從高階記憶體分配, 如果有. 高階記憶體在下一個子節描述.

F.GFP_NOFS,GFP_NOIO:這個標誌功能如同 GFP_KERNEL, 但是它們增加限制到核心能做的來滿足請求. 一個 GFP_NOFS 分配不允許進行任何檔案系統呼叫, 而 GFP_NOIO 根本不允許任何 I/O 初始化. 它們主要地用在檔案系統和虛擬記憶體程式碼, 那裡允許一個分配睡眠, 但是遞迴的檔案系統呼叫會是一個壞注意.

上面列出的這些分配標誌可以是下列標誌的相或來作為引數, 這些標誌改變這些分配如何進行:

  • __GFP_DMA

這個標誌要求分配在能夠 DMA 的記憶體區. 確切的含義是平臺依賴的並且在下面章節來解釋.

  • __GFP_HIGHMEM

這個標誌指示分配的記憶體可以位於高階記憶體.

  • __GFP_COLD

正常地, 記憶體分配器盡力返回”緩衝熱”的頁 — 可能在處理器緩衝中找到的頁. 相反, 這個標誌請求一個”冷”頁, 它在一段時間沒被使用. 它對分配頁作 DMA 讀是有用的, 此時在處理器緩衝中出現是無用的. 一個完整的對如何分配 DMA 快取的討論看”直接記憶體存取”一節在第 1 章.

  • __GFP_NOWARN

這個很少用到的標誌阻止核心來發出警告(使用 printk ), 當一個分配無法滿足.

  • __GFP_HIGH

這個標誌標識了一個高優先順序請求, 它被允許來消耗甚至被核心保留給緊急狀況的最後的記憶體頁.

  • __GFP_REPEAT
  • __GFP_NOFAIL
  • __GFP_NORETRY

這些標誌修改分配器如何動作, 當它有困難滿足一個分配. __GFP_REPEAT 意思是” 更盡力些嘗試” 通過重複嘗試 — 但是分配可能仍然失敗. __GFP_NOFAIL 標誌告訴分配器不要失敗; 它盡最大努力來滿足要求. 使用 __GFP_NOFAIL 是強烈不推薦的; 可能從不會有有效的理由在一個裝置驅動中使用它. 最後, __GFP_NORETRY 告知分配器立即放棄如果得不到請求的記憶體.

記憶體區段

__GFP_DMA和__GFP_HIGHMEM的使用與平臺相關,Linux把記憶體分成3個區段:可用於DMA的記憶體、常規記憶體、以及高階記憶體。X86平臺上ISA裝置DMA區段是記憶體的前16MB,而PCI裝置無此限制。

記憶體區後面的機制在 mm/page_alloc.c 中實現, 而記憶體區的初始化在平臺特定的檔案中, 常常在 arch 目錄樹的 mm/init.c。

kamlloc 的使用方法

Linux 處理記憶體分配通過建立一套固定大小的記憶體物件池. 分配請求被這樣來處理, 進入一個持有足夠大的物件的池子並且將整個記憶體塊遞交給請求者. 驅動開發者應當記住的一件事情是, 核心只能分配某些預定義的, 固定大小的位元組陣列.

如果你請求一個任意數量記憶體, 你可能得到稍微多於你請求的, 至多是 2 倍數量. 同樣, 程式設計師應當記住 kmalloc 能夠處理的最小分配是 32 或者 64 位元組, 依賴系統的體系所使用的頁大小. kmalloc 能夠分配的記憶體塊的大小有一個上限. 這個限制隨著體系和核心配置選項而變化. 如果你的程式碼是要完全可移植, 它不能指望可以分配任何大於 128 KB. 如果你需要多於幾個 KB, 但是, 有個比 kmalloc 更好的方法來獲得記憶體。在裝置驅動程式或者核心模組中動態開闢記憶體,不是用malloc,而是kmalloc ,vmalloc,或者用get_free_pages直接申請頁。釋放記憶體用的是kfree,vfree,或free_pages. kmalloc函式返回的是虛擬地址(線性地址). kmalloc特殊之處在於它分配的記憶體是物理上連續的,這對於要進行DMA的裝置十分重要. 而用vmalloc分配的記憶體只是線性地址連續,實體地址不一定連續,不能直接用於DMA.

注意kmalloc最大隻能開闢128k-16,16個位元組是被頁描述符結構佔用了。kmalloc用法參見khg.

記憶體對映的I/O口,暫存器或者是硬體裝置的RAM(如視訊記憶體)一般佔用F0000000以上的地址空間。在驅動程式中不能直接訪問,要通過kernel函式vremap獲得重新對映以後的地址。

另外,很多硬體需要一塊比較大的連續記憶體用作DMA傳送。這塊記憶體需要一直駐留在記憶體,不能被交換到檔案中去。但是kmalloc最多隻能開闢大小為32XPAGE_SIZE的記憶體,一般的PAGE_SIZE=4kB,也就是128kB的大小的記憶體。

2.kmalloc 和 vmalloc的區別

  • vmalloc()與 kmalloc()都可用於分配記憶體
  • kmalloc()分配的記憶體處於3GB~high_memory之間,這段核心空間與實體記憶體的對映一一對應
  • vmalloc()分配的記憶體在 VMALLOC_START~4GB之間,這段非連續記憶體區對映到實體記憶體也可能是非連續的
  • 在核心空間中呼叫kmalloc()分配連續物理空間,而呼叫vmalloc()分配非物理連續空間。
  • 把kmalloc()所分配核心空間中的地址稱為核心邏輯地址
  • 把vmalloc()分配的核心空間中的地址稱為核心虛擬地址
  • vmalloc()在分配過程中須更新核心頁表

3.總結:

1.kmalloc和vmalloc分配的是核心的記憶體,malloc分配的是使用者的記憶體

2.kmalloc保證分配的記憶體在物理上是連續的, kmalloc()分配的記憶體在0xBFFFFFFF-0xFFFFFFFF以上的記憶體中,driver一般是用它來完成對DS的分配,更適合於類似裝置驅動的程式來使用;

3.vmalloc保證的是在虛擬地址空間上的連續,vmalloc()則是位於實體地址非連續,虛地址連續區,起始位置由VMALLOL_START來決定,一般作為交換區、模組的分配。

3.kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相對較大(因為vmalloc還可以處理交換空間)。

4.記憶體只有在要被DMA訪問的時候才需要物理上連續,vmalloc比kmalloc要慢

5.vmalloc使用的正確場合是分配一大塊,連續的,只在軟體中存在的,用於緩衝的記憶體區域。不能在微處理器之外使用。

6.vmalloc 中呼叫了 kmalloc (GFP—KERNEL),因此也不能應用於原子上下文。

7.kmalloc和 kfree管理核心段內分配的記憶體,這是真實地址已知的實際實體記憶體塊。

8.vmalloc對應於vfree,分配連續的虛擬記憶體,但是物理上不一定連續。

9.kmalloc分配記憶體是基於slab,因此slab的一些特性包括著色,對齊等都具備,效能較好。實體地址和邏輯地址都是連續的

相關文章