核心中與驅動相關的記憶體操作之八 面向頁的記憶體分配

2021-06-20 09:35:44 字數 1971 閱讀 6949

1.概述:

當我們在核心驅動**中需要用到大量記憶體時,一般建議採用面向頁的記憶體管理.面向頁的記憶體管理有如下優點:

高效利用記憶體,避免記憶體碎片的產生.因為核心都是基於頁為基本單位去管理記憶體的.
面向頁的記憶體管理,顧名思義,就是以頁為基本單位來操作記憶體的.它比kmalloc()對記憶體使用上效率會高出很多.主要是兩種策略的記憶體粒度不一樣.面向頁的記憶體管理其粒度是page,而kmalloc的粒度是char.使用面向頁的記憶體管理不會導致記憶體的浪費,而kmalloc分配的記憶體會因為其粒度及系統對齊的要求而導致記憶體使用上的一定浪費.

2.核心中關於面向頁記憶體分配的api:

2-1:alloc_pages():

核心中關於面向頁記憶體分配的api最核心的為alloc_pages(),其他函式基本上都是封裝了它的.

函式原型:

static inline struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)

函式功能:

分配若干個頁.
引數說明:

gfp_mask:
此引數同 kmalloc 的用法相同.常常使用gfp_kernel或者gfp_atomic,可能帶有__gfp_dma 標誌( 給可能用在 isa dma 操作的記憶體 ) 或者__gfp_highmem 當可能使用高階記憶體時.

order:
order是你在請求的或釋放的頁數的以2為底的對數(即log2n).例如,如果你要乙個頁order 為0,如果你請求8頁就是3(2^3=8).

返回值:

成功返回一連續系列頁記憶體區域的首位址;失敗返回null.
2-2:常用申請頁api:

更為常用的申請頁api如下:

get_zeroed_page(unsigned int flags);
分配乙個頁面並清零

.

__get_free_page(gfp_mask);
類似於 get_zeroed_page, 但是沒有清零該頁.

__get_free_pages(unsigned int flags, unsigned int order);
分配並返回乙個指向乙個記憶體區第乙個位元組的指標, 記憶體區可能是幾個(物理上連續)頁長但是沒有清零.

其中,flags、gfp_mask和上述alloc_pages的引數gfp_mask意義一樣;ordef和上述alloc_pages()的引數order意義一樣.

2-3.釋放頁:

void free_page(unsigned long addr);

void free_pages(unsigned long addr, unsigned long order);

第乙個函式釋放乙個頁,第二個引數釋放若干個頁,需要和相應的頁申請函式配套使用.引數addr為申請頁的時候的記憶體首位址.order和上述alloc_pages()引數order一樣.

3.例項:

下面零星**來自ldd3.

基於面向頁分配記憶體: 

/* here's the allocation of a single quantum */

if (!dptr->data[s_pos])

基於面向頁釋放記憶體:

/* this code frees a whole quantum-set */

for (i = 0; i < qset; i++)

if (dptr->data[i])

free_pages((unsigned long)(dptr->data[i]), dptr->order);

核心中與驅動相關的記憶體操作之十 記憶體屏障

雖然實際驅動中不常用 但是閱讀核心比較深層的 經常會遇到 為什麼存在記憶體屏障呢 先看一下下面的場景 編譯器和處理器為了提高效率 可能對讀和寫操作重新進行了排序,例如 在某些處理器上 以下 a 1 b 2 有可能在 a中存放新值之前就在 b中存放新值.但是,我們在操作記憶體或者和硬體互動時 常常需要...

核心中與驅動相關的記憶體操作之十一 IO記憶體

裝置通常會提供一組暫存器用於控制裝置 讀定裝置和獲取裝置狀態 即控制暫存器 資料暫存器和狀態暫存器 這些暫存器可能位於 i o空間 也可能位於記憶體空間 當位於 i o空間時 通常被稱為 i o埠 位於記憶體空間時 對應的記憶體空間被稱為 i o記憶體 在嵌入式 linux中,我們接觸最多的就是 i...

Linux核心裝置驅動之核心中煉表的使用筆記整理

核心中煉表的應用 1 介紹 在linux核心中使用了大量的鍊錶結構來組織資料,包括裝置列表以及各種功能模組中的資料組織。這些鍊錶大多採用在include linux list.h實現的乙個相當精彩的鍊錶資料結構。鍊錶資料結構的定義很簡單 struct list head list head結構包含兩...