void *kmalloc(size_t size, int flags)
kmalloc函式和malloc函式相似,它有兩個引數,乙個引數是size,即申請記憶體塊的大小
,這個引數比較簡單,就像malloc中的引數一樣。第二個引數是乙個標誌,在裡面可以
指定優先權之類的資訊。在linux中,有以下的一些優先權:
gfp_kernel,它的意思是該記憶體分配是由執行在核心模式的程序呼叫的,即當記憶體低於
min_free_pages的時候可以讓
該程序進入睡眠;
gfp_atomic,原子性的內
存分配允許在
實際記憶體低於min_free_pages時繼續分配記憶體給
程序。gfp_dma:此標誌位需要和gfp_
kernel、gfp_atomic等一起使用,用來申請用於直接記憶體
訪問的記憶體頁。
1.kmalloc
在記憶體開闢中kmalloc的使用概率很高,在通常的記憶體開闢中均會使用該函式來開闢記憶體。但是分配的區域仍然保持原有的資料,一般需要清零。
函式原型:
void *kmalloc(size_t size ,int flags);
引數size很好理解,即是分配多大的記憶體,以位元組為單位。flags也很明白,即是分配的標誌,來控制kmalloc的行為。
flags一般常用的標誌有gfp_kernel,gfp_atomic,__gfp_dma。簡單說一下,gfp_kernel指由核心程序來執行的。使用這個flag時,函式會被阻塞,因為kmalloc允許當空閒頁比較少的時候,會睡眠等待空閒頁。而gfp_atomic則不然,他會立即呼叫核心預留的一些空閒頁,如果所有的預留都沒有了,就會立即返回錯誤。
該標誌一般用於中斷處理中。kmalloc一般最下處理32或64位元組,最大一般不超過128k。
kmalloc的原始碼如下
static __always_inline void *kmalloc(size_t size, gfp_t flags)
} return __kmalloc(size, flags); --如果不是常量的話 }
void *__kmalloc(size_t size, gfp_t flags) -- 這個函式與上面的類似可以說幾乎是一樣的,不知道這樣設計的含義
至於__get_free_pages和如何從後備快取記憶體中開闢物件,這個在理解記憶體管理的時候再去理解。到此可以說對於小頁的arch(即page_size=4k),kmalloc的size小於page_size時,會採用從已經建立好了的快取記憶體中分配記憶體物件。如果size不是2^n的話,會多開闢記憶體,有時最多開闢兩倍的記憶體,比如size=2^n+1時,最後開闢的記憶體會是2^(n+1),不過這種情況出現在size大於256時。為什麼這麼說呢?看下面的原始碼就可以理解了在kmalloc_slab函式中會呼叫kmalloc_index來查詢size所對應的快取記憶體物件。至於為什麼會出現這種情況,以後在看記憶體預分配高速緩衝時再說。原始碼如下:
static __always_inline int kmalloc_index(size_t size)
這這裡主要是理解kmalloc時,size的大小與真實核心分配記憶體間的關係,以及對於不同的開闢不同的記憶體大小則採用不同的辦法去開闢。對於大於page_size的size採用__get_free_pages開闢,而小於page_size的則採用從已經預建立好的快取記憶體物件中開闢。
2.vmalloc
vmalloc分配的內存在虛擬空間是連續的,而在物理空間可能是不連續的。適用於開闢大塊連續的,僅僅在軟體中存在,用於緩衝的記憶體。vmalloc需要查詢核心虛擬空間、的空閒節點,在空閒區域內建立頁表。其所消耗的資源遠比kmalloc多。所以不適合適用vmalloc去開闢小的記憶體,這種情況下,效率會很低。至於vmalloc如何去開闢記憶體空間以及建立新的頁表,還是來看原始碼的實現。在這裡不怎麼考慮標誌符的影響,先考慮一般情況下的vmalloc的實現 vmalloc函式實現在vmalloc.c中vmalloc->__vmalloc_node,__vmalloc_node除去檢測的**,其主要功能就是呼叫下面的兩個函式。
static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,int node, void *caller)
__get_vm_area_node主要是查詢核心虛擬空間中的空閒節點,從start到end之間查詢乙個空閒的vm塊
static struct vm_struct *__get_vm_area_node(unsigned long size,unsigned long flags, unsigned long start, unsigned long end,int node, gfp_t gfp_mask, void *caller)
area->next = *p; --將該vm塊新增到鍊錶
*p = area;
write_unlock(&vmlist_lock);
return area; }
__get_vm_area_node從核心空間查詢到大小滿足size,一般是大於size的,並且位址連續的乙個vm塊,並且對vm_struct進行賦值。而在__vmalloc_area_node中則是將上面查詢的vm_struct的記憶體進行建立新頁。在上面函式中只是查詢到一段連續的記憶體,並沒有將記憶體分頁,建立新的頁鍊錶
static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,pgprot_t prot, int node, void *caller)
else
area->pages = pages;
area->caller = caller;
if (!area->pages)
for (i = 0; i < area->nr_pages; i++)
return area->addr; }
到此vmalloc就開闢出新的虛擬並連續的記憶體。vmalloc其實是在核心虛擬空間中找出滿足size的記憶體節點,然後在該節點中建立新的頁表。這也是為什麼在開闢小的記憶體時採用vmalloc是不划算的。而且vmalloc對於物理記憶體而言並沒有什麼意義,因為在物理記憶體中,vmalloc開闢的記憶體並不連續。其主要是對軟體有意義。
3.__get_free_pages
在上面也提到__get_free_pages,該函式會在kmalloc開闢空間大於page_size時呼叫。
__get_free_pages ->alloc_pages ->alloc_pages_node->__alloc_pages->__alloc_pages_internal 經過七拐八拐的最終會分配新頁這個函式,這個函式是zone區分配器的核心。
__alloc_pages_internal這個函式以後再了解記憶體管理時,再好好理解,現在很難。
4.kmem_cache_create與kmem_cache_alloc
這兩個函式是組合起來一起用,kmem_cache_create用於建立乙個高速緩衝物件,而kmem_cache_alloc用於分配高速緩衝物件記憶體。這個一般用於需要頻繁開闢和登出同一種結構的物件,這個也是用於加速。
5.dma_alloc_coherent
這個函式分配緩衝區並且重新對映。分配的記憶體可以用於dma的傳輸。
6. alloc_bootmem
有時候某些核心模組需要開闢較大的記憶體如幾m的記憶體空間,如果在記憶體管理建立後去開闢容易流於失敗,通常會在引導程式時提前開闢,這樣會跳過核心的記憶體管理,對記憶體管理而言,這樣的空間是不可見的。這樣會減少留給作業系統的ram。這段記憶體也需要自己去管理。這個我喜歡!!
7. ioremap
ioremap這個函式不能是乙個真正的記憶體分配,不過他也是乙個記憶體分配,為什麼這麼說呢?因為ioremap的記憶體可以將記憶體管理系統看不見的硬體記憶體對映到虛擬記憶體中,說他是記憶體分配,因為他是分配純虛擬空間。說他不是,因為他不分配真實的物理空間,他是一種對映。
例如:現在物理記憶體128m,但是在傳替給核心引數時卻是 「mem = 124m」,那對用linux系統而言,真實的記憶體就是124m那還有的4m就無法使用了。這個時候就可以採用ioremap的辦法,將在流離在外的4m給弄來,ioremap(0x7c00000,0x400000);這樣就可以將那4m給對映到記憶體中,不過這個還是需要自己去管理的。
以上就是一些記憶體分配的常用的機制。至於具體的實現辦法以後再學習記憶體管理機制的時候,在去看看。
vector記憶體的開闢與
1.vector的記憶體增長vector其中乙個特點 記憶體空間只會增長,不會減小,援引c primer 為了支援快速的隨機訪問,vector容器的元素以連續方式存放,每乙個元素都緊挨著前乙個元素儲存。設想一下,當vector新增乙個元素時,為了滿足連續存放這個特性,都需要重新分配空間 拷貝元素 撤...
動態開闢記憶體總結
動態開闢記憶體是在程式執行過程中進行開闢空間的,主要在堆,棧中開闢 有關堆中動態開闢記憶體空間的函式有malloc,calloc,realloc,free。棧中開闢空間的有alloca。void malloc size t size void calloc size tnum,size tsize ...
動態記憶體開闢
記憶體分配有三種方式 1.從靜態儲存區分配,生命週期隨程式的結束而結束,比如全域性變數,static變數 2.從棧空間分配,函式呼叫完其被自動釋放 3.從堆空間分配,即動態記憶體開闢,比如 malloc,calloc,realloc,何時申請何時釋放 malloc 函式原型void malloc s...