linux核心把物理頁作為記憶體管理的基本單位。每一頁的大小根據系統架構不同有所區別,32位系統下為4kb,64位系統下為8kb。記憶體管理單元(mmu)以頁為單位來管理系統中的頁表,負責虛擬位址到實體地址的轉換,使用者所使用的記憶體位址一般都是虛擬位址。
核心中頁的結構體中比較重要的成員為:
struct page ;
記憶體中區的劃分:
名稱
物理記憶體
描述
zone_dma
0~16mb
dma使用的記憶體
zone_normal
16~896mb
正常可定址的記憶體
zone_highem
896mb之後的記憶體
動態對映的記憶體
區的劃分實際是和體系結構相關,如x86體系結構下,isa裝置只能在物理記憶體的前16mb執行dma。所以在某些體系結構下,zone_dma和zone_normal可能合併為zone_normal。高階記憶體zone_highem也是類似。不同的區組成了不同的記憶體池,記憶體池的主要作用是減少記憶體碎片。
核心中區也有對應的結構體(省略部分):
struct zone lru[nr_lru_lists];
struct zone_reclaim_stat reclaim_stat;
unsigned long pages_scanned; /* since last reclaim */
unsigned long flags; /* zone flags, see below */
/* zone statistics */
atomic_long_t vm_stat[nr_vm_zone_stat_items];
int prev_priority;
unsigned int inactive_ratio;
unsigned long wait_table_hash_nr_entries;
unsigned long wait_table_bits;
struct pglist_data *zone_pgdat;
/* zone_start_pfn == zone_start_paddr >> page_shift */
unsigned long zone_start_pfn;
unsigned long spanned_pages; /* total size, including holes */
unsigned long present_pages; /* amount of memory (excluding holes) */
const char *name;
}核心中總共就三個區,所以也只有3個這樣的結構,name分別為「dma」、「normal」、「highmem」。
頁的操作介面:
static inline struct page *
alloc_pages(gfp_t gfp_mask, unsigned int order) 請求多個記憶體頁,返回指向第乙個頁的page結構體
void *page_address(struct page *page) 把給定的頁轉換成虛擬位址,返回虛擬位址
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order) 相當於上面兩個函式一起執行的結果,返回第乙個頁的邏輯位址
unsigned long get_zeroed_page(gfp_t gfp_mask) 請求填充為0的頁
void __free_pages(struct page *page, unsigned int order) 釋放頁,入參為page
void free_pages(unsigned long addr, unsigned int order) 釋放頁,入參為邏輯位址
我們常用的是以位元組為單位的分配,
位元組記憶體的操作介面:
void *kmalloc(size_t size, gfp_t flags) 用來分配實體地址連續的記憶體。
void kfree(const void *) 用來釋放kmalloc函式分配的記憶體。
void *vmalloc(unsigned long size)用來分配虛擬位址連續的記憶體,不要求實體地址連續。
void vfree(const void *addr)用於釋放vmalloc分配的記憶體
以上的記憶體分配介面都涉及到gfp_mask標誌,這裡不進行細說,例舉幾個常用的:
標誌
描述
gfp_kernel
常規分配方式,可能會阻塞。這個標誌在睡眠安全時用在程序上下文**中。一般為首選標誌。
gfp_atomic
用於中斷處理程式、下半部等不能睡眠的地方
gfp_dma
從zone_dma進行分配,通常與其他標誌組合使用
針對頻繁申請和釋放資料結構場景(如檔案描述符、程序描述符等)實現了slab分配器,slab分配器將不同的物件劃分快取記憶體組,每個快取記憶體組都存放不同的物件,每種物件型別對應乙個快取記憶體。kmalloc()介面建立在slab層之上,使用了一組通用快取記憶體。每個快取記憶體又可分為乙個或多個slab,通常乙個slab由乙個頁組成。
每個slab處於三種狀態之一:滿、部分滿、空。slab在核心中也對應著乙個結構體:
struct slab ;
slab描述有兩種存放的選擇:一種是存放在slab自身開始的地方,另一種是在slab之外另行分配。slab分配器建立新的slab時,可以kmem_get_pages()。使用kmem_freepages釋放記憶體。
建立快取記憶體介面如下:
struct kmem_cache *
kmem_cache_create (const char *name, size_t size, size_t align,
unsigned long flags, void (*ctor)(void *))
第乙個引數為快取記憶體名稱,第二個引數快取記憶體中每個元素的大小,第三個引數為slab內第乙個物件的偏移,通常為0。最後乙個是快取記憶體的建構函式,新頁追加到快取記憶體時才被呼叫。成功返回乙個指向快取記憶體的指標,失敗返回 null。
void kmem_cache_destroy(struct kmem_cache *);
撤銷快取記憶體
void *kmem_cache_alloc(struct kmem_cache *cachep,
gfp_t flags)
從快取記憶體中分配物件,第二個引數通常是gfp_kernel或gfp_atomic
void kmem_cache_free(struct kmem_cache *cachep, void *objp)
釋放物件,放回slab中。第乙個為快取記憶體,第二個為需要釋放的物件位址
核心中也存在程序的概念,每個核心程序都有兩頁的核心棧。所以核心程序中盡量避免靜態分配,節省棧空間。
高階記憶體的頁不能永久對映到核心位址空間上,使用alloc_pages()+__gfp_highmem標誌來獲得的頁不具有虛擬位址,還需要使用kmap()將頁對映到核心位址空間,通常是3g~4g。該對映函式可以睡眠,只能用於程序上下文。使用kunmap()可以解除對映。在中斷上下文,可用kmap_atomic()來對映高階記憶體,kunmap_atomic()可以解除對映。
最後,核心實現了一種叫"per cpu"變數,我們稱為每cpu變數,實際就是定義了乙個陣列,長度為cpu數量,每乙個元素只能由對應的cpu處理。這樣可以避免併發訪問的問題,處理器可以不加鎖的情況下進行安全訪問。如:
long my_percpu[nr_cpus];
int cpu;
cpu=get_cpu(); //獲取當預處理器,並禁止核心搶占
my_percpu[cpu]++;
put_cpu() //啟用核心搶占
可以看到,在cpu訪問每cpu變數時,禁止了核心搶占,這是為了防止某些cpu可以接觸到其他cpu的資料。
define_per_cpu(type,name) 編譯時建立型別為type,名字為name的變數
declare_per_cpu(type,name) 宣告每cpu變數
get_cpu_var() 返回當預處理器變數,同時禁止搶占,如:get_cpu_var()++;
put_cpu_var() 啟用核心搶占
per_cpu(name,cpu)++ 增加指定cpu上name變數的值
void* alloc_percpu(type) 動態分配type型別的每cpu變數
void* __alloc_percpu(size_t size, size_t align) 增加了位元組對齊
void free_percpu(const void *); 釋放每cpu變數
核心學習之記憶體定址(一)
端選擇符和段暫存器 邏輯位址 48位 由段選擇符 16位 和偏移量 32位 組成 t1 0表示gdt,1表示ldt 段暫存器 16位 用來儲存段選擇符,由於段描述符為8位元組,因此,索引號只需要13位元組即可 cs 段暫存器,指向包含程式指令的段。它包含兩位的字段 cpl 0表示核心態,3表示使用者...
linux 核心學習之記憶體管理 未完待續
1 相關概念 mmu mmu是memory management unit的縮寫,中文名是 記憶體管理 單元,它是 處理器 cpu 中用來管理 虛擬儲存器 物理儲存器的控制線路,同時也負責 虛擬位址 對映為實體地址 以及提供硬體機制的記憶體訪問授權。頁 記憶體管理 物理頁 的基本單位 mmu通常以頁...
linux核心學習筆記(2) 記憶體定址
硬體中的分頁 頁框是乙個儲存區域,頁是乙個資料塊。兩者的長度一致 乙個 每個頁框包含乙個頁。4kb 1 directory 最高10位 2 table 中間10位 3 offset 最低12位 兩級頁表 兩級表的第一級表稱為頁目錄,儲存在乙個4k位元組的頁中,頁目錄表共有1k個表項,每個表項為4個位...