內存分配的API有:alloc_pages, kmalloc, slab分配,vmalloc, malloc,下面簡單說明一下以上幾個函數的差別:
alloc_pages:主要用來從buddy系統中分配內存,以頁爲單位分配區域需要通過gfp_flag指定,一般情況下會優先從highmem zone分配,返回的是分配到物理首個頁面的管理結構體struct page,buddy裏面頁面的組織情況如下圖:
alloc_pages返回的是滿足條件的用於管理free_area中對應大小的block的page struct的地址,同時每個free_area元素的migrationtype中的內存block的管理者都通過page組成的lru鏈表管理,而alloc_pages返回的是通過list_entry來獲取這個lru鏈表中的一個page struct返回,從管理頁面的角度,buddy可以化成如下示意圖:
而alloc_pages如果分配的order是小於等於4,則返回的是上圖中其中一個page struct
kmalloc和slab:kmalloc是slab的一個通用分配內存API,slab分配器從buddy拿到需求大小且物理內存連續的物理頁面個數,然後kmalloc再從slab分配器中獲取需要的slab對象,slab對象大小可以爲64,128,256等等個字節數,相對於專用的slab分配內存主要是部分驅動申請的slab描述符,然後再進行slab對象的內存申請。此時申請的物理內存是連續的
vmalloc:再kernel space的vmalloc area中申請內存,並建立虛擬地址到物理地址映射,此時的物理地址可能是不連續的,因爲在申請內存時時一個頁面一個頁面alloc_pages,後面建立映射過程中也是一個頁面一個頁面映射。
static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
pgprot_t prot, int node)
{
………………
for (i = 0; i < area->nr_pages; i++) {
struct page *page;
if (node == NUMA_NO_NODE)
page = alloc_page(alloc_mask);
else
page = alloc_pages_node(node, alloc_mask, order);
if (unlikely(!page)) {
/* Successfully allocated i pages, free them in __vunmap() */
area->nr_pages = i;
goto fail;
}
area->pages[i] = page;
if (gfp_mask & __GFP_WAIT)
cond_resched();
}
………………
}
static int vmap_pte_range(pmd_t *pmd, unsigned long addr,
unsigned long end, pgprot_t prot, struct page **pages, int *nr)
{
………………
do {
struct page *page = pages[*nr];
if (WARN_ON(!pte_none(*pte)))
return -EBUSY;
if (WARN_ON(!page))
return -ENOMEM;
set_pte_at(&init_mm, addr, pte, mk_pte(page, prot));
(*nr)++;
} while (pte++, addr += PAGE_SIZE, addr != end);
return 0;
}
malloc:主要是在進程的虛擬地址空間user space中申請vma,但是此時並沒有分配物理內存,除分配flag帶有VM_MLOCK標誌需要立即建立虛擬地址到物理地址的映射外,其他都是在進程需要訪問此虛擬內存時,通過缺頁中斷來申請的物理地址,並建立映射,另外malloc申請到的物理內存也是不連續的。
mmap:在私有內存映射中,當malloc申請的內存size大於128KB時,glibc會自動使用mmap來代替brk分配內存。