記憶體對映結構:
1.32位位址線定址4g的記憶體空間,其中0-3g為使用者程式所獨有,3g-4g為核心占有。
2.struct page:整個物理內存在初始化時,每個4kb頁面生成乙個對應的struct page結構,這個page結構就獨一無二的代表這個物理記憶體頁面,並存放在mem_map全域性陣列中。
3.段式對映:首先根據**段選擇子cs為索引,以gdt值為起始位址的段描述表中選擇出對應的段描述符,隨後根據段描述符的基址,本段長度,許可權資訊等進行校驗,校驗成功後。cs:offset中的32位偏移量直接與本段基址相累加,得出最終訪問位址。
0-3g與mem_map的對映方式:
因linux中採用的段式對映為flat模式,所以從邏輯位址到線性位址沒有變化。從段式出來進入頁式,每個使用者程序都獨自擁有乙個頁目錄表(pdt),執行時存放於cr3。 cr3(頁目錄) + 前10位 => 頁面表基址 + 中10位 => 頁表項 + 後12位 => 物理頁面位址
3g-4g與mem_map的對映方式:
分為三種型別:低端記憶體/普通記憶體/高階記憶體。
低端記憶體:3g-3g+16m 用於dma __pa線性對映
普通記憶體:3g+16m-3g+896m __pa線性對映 (若物理記憶體<896m,則分界點就在3g+實際記憶體)
高階記憶體:3g+896-4g 採用動態的分配方式
4.高階記憶體(假設3g+896為高階記憶體起址)
作用:訪問到1g以外的物理記憶體空間。
線性位址共分為三段:vmalloc段/kmap段/kmap_atomic段(針對與不同的記憶體分配方式)
從記憶體分配函式的結構來看主要分為下面幾個部分:
a.夥伴演算法(最原始的面向頁的分配方式)
alloc_pages 介面:
struct page * alloc_page(unsigned int gfp_mask)——分配一頁物理記憶體並返回該頁物理記憶體的page結構指標。
struct page * alloc_pages(unsigned int gfp_mask, unsigned int order)——分配 個連續的物理頁並返回分配的第乙個物理頁的page結構指標。
《釋放函式:__free_page(s)>
核心中定義:#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
最終都是呼叫 __alloc_pages.
其中max_order 11,及最大分配到到頁面個數為2^10(即4m)。
void *page_address(struct page *page);
低端記憶體的對映方式:__va((unsigned long)(page - mem_map) << 12)
高階記憶體到對映方式:struct page_address_map分配乙個動態結構來管理高階記憶體。(核心是訪問不到vma的3g以下的虛擬位址的) 具體對映由kmap / kmap_atomic執行。
get_free_page介面:(alloc_pages介面兩步的替代函式)
unsigned long get_free_page(unsigned int gfp_mask)
unsigned long __get_free_page(unsigned int gfp_mask)
unsigned long __get_free_pages(unsigned int gfp_mask, unsigned int order)
《釋放函式:free_page>
與alloc_page(s)系列最大的區別是無法申請高階記憶體,因為它返回到是乙個線性位址,而高階記憶體是需要額外對映才可以訪問的。
b.slab快取記憶體(反覆分配很多同一大小記憶體) 注:使用較少
kmem_cache_t* xx_cache;
建立: xx_cache = kmem_cache_create("name", sizeof(struct xx), slab_hwcache_align, null, null);
分配: kmem_cache_alloc(xx_cache, gfp_kernel);
釋放: kmem_cache_free(xx_cache, addr);
記憶體池mempool 不使用。
c.kmalloc(最常用的分配介面) 注:必須小於128kb
gfp_atomic 不休眠,用於中斷處理等情況
gfp_kernel 會休眠,一般狀況使用此標記
gfp_user 會休眠
__gfp_dma 分配dma記憶體
kmalloc/kfree
d.vmalloc/vfree
vmalloc採用高階記憶體預留的虛擬空間來收集記憶體碎片引起的不連續的物理記憶體頁,是用於非連續物理記憶體分配。
當kmalloc分配不到記憶體且無物理記憶體連續的需求時,可以使用。(優先從高階記憶體中查詢)
e.ioremap()/iounmap()
ioremap()的作用是把device暫存器和記憶體的實體地址區域對映到核心虛擬區域,返回值為核心的虛擬位址。使用的線性位址區間也在vmmlloc段
注:vmalloc()與 alloc_pages(_gfp_highmem)+kmap();前者不連續,後者只能對映乙個高階記憶體頁面
__get_free_pages與alloc_pages(normal)+page_address(); 兩者完全等同
核心位址通過 __va/__pa進行中低記憶體的直接對映
高階記憶體採用kmap/kmap_atomic的方式來對映
個人總結如下:
a.在<128kb的一般記憶體分配時,使用kmalloc
允許睡眠:gfp_kernel
不允許睡眠:gfp_atomic
b.在》128kb的記憶體分配時,使用get_free_pages,獲取成片頁面,直接返回虛擬位址(<4m)(或alloc_pages + page_address)
c.b失敗,
如果要求分配高階記憶體:alloc_pages(_gfp_highmem)+kmap(僅能對映乙個頁面)
如果不要求記憶體連續: 則使用vmalloc進行分配邏輯連續的大塊頁面.(不建議)/分配速度較慢,訪問速率較慢。
d.頻繁建立和銷毀很多較大資料結構,使用slab.
e.高階記憶體對映:
允許睡眠:kmap (永久對映)
不允許睡眠:kmap_atomic (臨時對映)會覆蓋以前到對映(不建議)
Linux記憶體分配方式
linux核心中常見記憶體分配函式 原理說明 linux核心中採用了一種同時適用於32位和64位系統的記憶體分頁模型,對於32位系統來說,兩級頁表足夠用了,而在x86 64系統中,用到了四級頁表,如圖2 1所示。四級頁表分別為 頁全域性目錄 page global directory 頁上級目錄 p...
java的記憶體分配方法
記憶體分配方法主要可以分為 堆 heap 靜態區域 由static修飾 棧 stack 常量池 其中,堆和常量池主要存放 右邊的 值 而棧和靜態區域則主要存放 左邊的變數 名 或者引用 名 舉幾個栗子 1 string str abc static int a 10 str stack 因為是 變數...
記憶體分配方式
記憶體分配方式有三種 1 從靜態儲存區域分配。內存在程式編譯的時候就已經分配好,這塊內存在程式的 整個執行期間都存在。例如全域性變數,static 變數。2 在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函 數執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指...