几个内存分配API的区别

内存分配的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分配内存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章