萬盛學電腦網

 萬盛學電腦網 >> Linux教程 >> inux內存分配方法解析

inux內存分配方法解析

  內存映射結構:

  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);

copyright © 萬盛學電腦網 all rights reserved