linux核心學習 記憶體管理

2021-06-19 17:08:55 字數 3207 閱讀 8084

核心把物理頁作為記憶體管理的基本單位。

32位系統:4k / 頁

64位系統:8k / 頁

由於硬體限制,核心不能對所有頁一視同仁。linux必須處理如下硬體存在的缺陷而引起的記憶體定址問題:

linux主要使用了四種區:

zone_dma —— 這個區包含的頁只能用來執行dma操作

zone_dma32 —— 和zone_dma類似,但只能被32位裝置訪問

zone_normal —— 這個區包含的頁都是能正常對映的頁

zone_highem —— 這個區包含「高階記憶體」,不能永久對映到核心位址空間

x86-32上的頁

描述物理記憶體

zone_dma

dma使用的頁

< 16m

zone_normal

正常定址的頁

16m ~ 896m

zone_highem

動態對映的頁

> 896m

低階頁分配方法函式

描述struct page * allock_page(gfp_mask)

只分配一頁,返回指向頁結構的指標

struct page * allock_page(gfp_mask, order)

分配2的order次方個頁,返回指向第乙個頁結構的指標

unsigned long __get_free_page(gfp_mask)

只分配一頁,返回指向企邏輯位址的指標

unsigned long __get_free_pages(gfp_mask, order)

分配2的order次方個頁,返回指向第一頁邏輯位址的指標

unsigned long get_zoned_page(gfp_mask)

只分配一頁,讓其內容填充0,返回指向企邏輯位址的指標

頁釋放函式函式原型

描述void __free_pages(struct page * page, unsigned int order)

釋放page頁位址開始的2的order次方個頁

void free_pages(unsigned long addr, unsigned int order)

釋放addr位址開始的2的order次方個頁

void free_page(unsigned long addr)

釋放addr位址開始的乙個頁

struct page * allock_pages(gfp_t gfp_mask, unsigned int order)

該函式分配2的order次方個連續的物理頁,並返回指向第乙個頁的page結構體指標;如果出錯返回null。

void * page_address(struct page * page)

e.g.獲得8個頁,然後釋放:

unsigned long page;

page = __get_free_pages(gfp_kernel, 3);     //申請8個頁

if (!page)

return -enomem;        //沒有足夠記憶體

free_pages(page, 3);    //釋放

gfp_kernel是gfp_mask標誌的一種,後邊有說明

按位元組分配及釋放記憶體函式函式原型

描述void * kmalloc(size_t, gfp_t flags)

按照flags標誌分配至少size位元組大小的記憶體,且物理連續,返回指向記憶體塊的指標

void * vmalloc(unsigned long size)

按照flags標誌分配至少size位元組大小的記憶體,虛擬位址連續,實體地址不一定連續,返回指向記憶體塊的指標

void kfree(const void *ptr)

釋放由kmalloc申請的記憶體空間

void vfree(const void *addr)

釋放由vmalloc申請的記憶體空間

kmalloc 和 vmalloc的區別在於:

kmalloc()分配的是實體地址連續的記憶體(邏輯位址自然也是連續的),該函式是否允許休眠通過其引數flags來決定。

vmalloc()函式只確保頁在虛擬位址空間內是連續的,它通過分配非連續的物理記憶體塊,再「修正」頁表,把記憶體對映到邏輯位址空間的連續區域。

因此,該函式可能睡眠,不能在中斷上下文進行呼叫,也不能從其他不允許組賽的情況下呼叫。

出於效能考慮,核心**多用kmalloc()來獲得記憶體。

不管是在低階頁分配函式中,還是在kmalloc()中,都用到了分配器標誌。這些標誌可分為三類:行為修飾符、區段修飾符及型別。

行為修飾符表示你核心該如何分配所需記憶體,如:中斷處理程式需要核心分配記憶體過程中不能睡眠。

常用的行為修飾符標誌

描述__gfp_wait

分配器可以睡眠

__gfp_io

分配器可以啟動磁碟io

__gfp_fs

分配器可以啟動檔案系統io

__gfp_high

分配器可以訪問緊急事件緩衝池

區修飾符表示從哪個區中進行分配,zone_dma、zone_normal還是zone_highem。

區修飾符標誌

描述__gfp_dma32

從zone_dma分配

__gfp_dma32

只在zone_dma32分配

__gfp_highmem

從zone_highmem或zone_normal分配

型別標誌是行為修飾符和區修飾符的組合,如:gfp_kernel  =  (__gfp_wait  |  __gfp_io  |  __gfp_fs)

常用的型別標誌標誌

描述gfp_atomic

這個標誌用在中斷處理程式、下半部、持有自旋鎖以及其他不能睡眠的地方

gfp_kernel

這是一種常規分配方式,可能會阻塞。這個標誌在睡眠安全時用在程序上下文**中,

為了獲得呼叫者所需的記憶體,核心會盡力而為。這個標誌應當是首選標誌

請參考:

linux 核心學習 1 記憶體管理

1 分頁機制 早期計算機直接使用實體地址進行記憶體的使用和管理,但是硬體資源有限,而且不同的程式需要使用不同的實體地址,這樣給程式的管理和執行造成了很大的難度,而且極易造成乙個程式覆蓋其他程式的問題,使正常執行的程式出現錯誤。針對以上問題提出了使用虛擬位址與物理位址對映的管理方式,這樣每個程式都可以...

Linux 核心學習 4 記憶體管理

注 以下 有的是linux 5.10,有的是linux 2.6.30.4 1 arch x86 boot memory.c static void detect memory e820 void desc buf count while ireg.ebx count array size boot ...

linux核心學習筆記之記憶體管理

linux核心把物理頁作為記憶體管理的基本單位。每一頁的大小根據系統架構不同有所區別,32位系統下為4kb,64位系統下為8kb。記憶體管理單元 mmu 以頁為單位來管理系統中的頁表,負責虛擬位址到實體地址的轉換,使用者所使用的記憶體位址一般都是虛擬位址。核心中頁的結構體中比較重要的成員為 stru...