Linux核心記憶體配置函數

來源:互聯網
上載者:User

Linux核心中記憶體的管理不像在核心外這麼簡單。和使用者空間最大的不同是核心的內從空間不像使用者空間那麼容易得到,並不是總能輕易的得到想要的記憶體。

頁:

核心最基本的記憶體管理單元就是頁(page),因為MMU管理的記憶體基本單位是page,其維護著提供虛擬位址到物理地址轉換的頁表。

核心使用如下資料結構表述page:

 

struct page { 

    unsigned long         flags; //the status of the page,eg if the page is dirty,is locked

 

    atomic_t              _count; //the references to this page 

    atomic_t              _mapcount; 

    unsigned long         private; 

    struct address_space  *mapping; 

    pgoff_t               index; 

    struct list_head      lru; 

    void                  *virtual;//the page's virtual space

};

需要注意的page資料結構是對機器中所有實體記憶體的描述並關心頁中具體的資料,它只關心諸如page是否空閑,誰在佔用這個page等等。

區:

核心將整個記憶體分為三個區(zone)。

ZONE_DMA--可進行DMA的記憶體空間,在x86中是低於16M的地址空間

ZONE_NOMAL--在x86中是16M-896M的空間,這部分空間是永久直接映射到核心地址空間的

ZONE_HIGHMEM--動態映射的地址空間

為什麼要分區呢?因為在一些體系(如x86)中只有部分記憶體是可以直接映射的,對x86在896M以上的記憶體都是動態映射的,所以核心對記憶體分區描述顯得必要,DMA分區是能夠進行DMA操作的記憶體空間。

核心頁分配介面:

核心提供若干以page為配置單位的記憶體配置函數。

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

分配2的order次方個連續的頁面,返回指向第一個page的指標。當然在實際中我們一般針對分配的記憶體的虛擬位址進行操作,下面這個

void * page_address(struct page *page);

返回page的邏輯地址指標。

當然為了方便核心也提供直接返回虛擬位址指標的函數,實際就是封裝了這兩個函數:

unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);

還有直接分配單個page的函數,實際就是order參數為0的版本:

 

struct page * alloc_page(gfp_t gfp_mask) ;

unsigned long __get_free_page(gfp_t gfp_mask);

如果你想獲得的頁面全部被初始化為0,核心提供這個調用:

get_zeroed_page(gfp_mask);

工作方式和__get_free_pages相同,除了該函數會將核心空間初始化為0。

這些函數都有相對應的頁面釋放函數,原型如下:

 

void __free_pages(struct page *page, unsigned int order) ;

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

void free_page(unsigned long addr);

更常用的分配介面:

除了原始的以頁為單元的記憶體配置函數,核心還提供更為方便的和C語言中介面類似的分配介面,最常用的就是kmalloc函數:

void * kmalloc(size_t size, gfp_t flags);

該介面返回至少size位元組的物理連續的記憶體空間。用法和c語言malloc函數一樣。

當然還有類似free的記憶體釋放函數

void kfree(const void *ptr);

核心還提供vmalloc函數,用法和kmalloc一樣,唯一的不同的vmalloc不保證分配的記憶體是物理連續的。

怎麼選擇用哪個分配函數呢?大多數情況下,我們需要分配的記憶體並沒有需要是物理連續的,除了外設操作的記憶體需要記憶體連續,因為對很多外設來說並沒有邏輯記憶體的概念,他只能看到和操作實體記憶體。其他情況下,我們並沒有一定要使用連續實體記憶體的需要。然而事實是,大多是情況下,核心中還是使用kmalloc來分配記憶體,這基本上是基於效率考慮。因為vmalloc調用為了使不連續實體記憶體的邏輯地址連續會有很多附加對頁表的操作,所以除了必須(需要使用相當大的記憶體空間),一般情況直接使用kmalloc函數。

vmalloc也有對應的vfree函數。

gfp_mask參數:

gfp_mask參數可以設定很多值,一下是各個取值的用處(直接引用至LKD):

GFP_ATOMIC  The allocation is high priority and must not sleep. This is the flag to use in interrupt handlers, in bottom halves, while holding a spinlock, and in other situations where you cannot sleep.

GFP_NOWAIT  Like GFP_ATOMIC, except that the call will not fallback on emergency memory pools. This increases the liklihood of the memory allocation failing.

GFP_NOIO  This allocation can block, but must not initiate disk I/O. This is the flag to use in block I/O code when you cannot cause more disk I/O, which might lead to some unpleasant recursion.

GFP_NOFS  This allocation can block and can initiate disk I/O, if it must, but it will not initiate a filesystem operation. This is the flag to use in filesystem code when you cannot start another filesystem operation.

GFP_KERNEL  This is a normal allocation and might block. This is the flag to use in process context code when it is safe to sleep. The kernel will do whatever it has to do to obtain the memory requested by the caller. This flag should be
your default choice.

GFP_USER  This is a normal allocation and might block. This flag is used to allocate memory for user-space processes.

GFP_HIGHUSER  This is an allocation from ZONE_HIGHMEM  and might block. This flag is used to allocate memory for user-space processes.

GFP_DMA  This is an allocation from ZONE_DMA. Device drivers that need DMA-able memory use this flag, usually in combination with one of the preceding flags.

使用SLAB緩衝分配:

當需要頻繁的針對特定資料結構分配和釋放記憶體時,為了避免反覆記憶體配置和釋放的開銷,Linux核心提供了強大的記憶體緩衝分配策略,即SLAB緩衝分配。(實際上kmalloc函數就是建立在slab分配器上的!)

每個slab包含一定數量的對象,即需要被緩衝的資料結構,每個slab都有三個狀態:full,partial,empty。當試圖從slab中分配一個object時,核心優先從partial的slab中擷取對象,不行則從empty slab中,如果全部是full則建立一個新的slab。核心中管理slab緩衝的組成主要有cache,slab,object.

cache在核心中使用 kmem_cache結構來描述,包含三個鏈表--—slabs_full, slabs_partial, 以及slabs_empty。這些list中就包含相應狀態的slab,slab在核心中的描述如下:

 

struct slab { 

    struct list_head  list;       /* full, partial, or empty list */ 

    unsigned long     colouroff;  /* offset for the slab coloring */ 

    void              *s_mem;     /* first object in the slab */ 

    unsigned int      inuse;      /* allocated objects in the slab */

    kmem_bufctl_t     free;       /* first free object, if any */ 

 

};

下列函數可以建立一個新的cache:

 

struct kmem_cache * kmem_cache_create(const char *name, size_t size, 

                                                                   size_t align, unsigned long flags, void (*ctor)(void *));

各個參數說明如下:

const char *name:cache的名稱。

size_t size:cache中需要緩衝的object的大小。

size_t align:slab中第一個object的位移,一般0即可,使用標準對齊。

unsigned long flags:可以為緩衝分配執行一些附加操作,沒有的話直接0即可。

void (*ctor)(void *):cache的建構函式,你可以賦值一個函數地址,當新的page加入cache後一定會執行該建構函式。可以複賦值為NULL。

銷毀一個cache時使用

int kmem_cache_destroy(struct kmem_cache *cachep);

核心提供兩個函數負責從指定的cache擷取和交還記憶體:

void * kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);

void kmem_cache_free(struct kmem_cache *cachep, void *objp);

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.