本文主要介绍内存申请的函数介绍:
1.vmalloc kmalloc 是用来分配内核空间内存的,malloc是用来分配用户空间的内存的。kmalloc分配的页在物理地址上是连续的(虚拟地址自然也是连续的), vmalloc只确保
页在虚拟地址空间内是连续的。它通过非连续的物理内存块,再“修正”页表,把内存映射到逻辑地址空间是连续的区域内。 malloc 返回的也在进程的虚拟地址空间内是连续
的,但是在物理地址上不一定是连续的。
2. 用于kmalloc可分配的内存大小范围在32~131027(128k)字节,并且由于它用slab分配器来分配内存的,所以,得到的内存大小可能比你申请的要大一些(它向上取2的N次
幂整数)。而且如果开启了CONFIG_LARGE_ALLOCS选项,这个值可以更大,可以达到了32M。一般申请较大的内存才使用vmalloc,例如当模块被动态加载到内核当中时,
就把模块装载到由vmalloc()分配 的内存上。
3.vmalloc是会睡眠的,因此不能在中断上下文中使用。 kmalloc可以通过配置flags配置为可睡眠或者不可睡眠,GFP_KERNEL可以睡眠 ,GFP_ATOMIC不可以睡眠。
4.内核中vmalloc,kmalloc分配都是以字节为单位,若想以页为单位用alloc_pages类函数。 当然,内核进行内存管理(MMU干的)是以物理页为基本单位的。
简单的说:
- kmalloc和vmalloc是分配的是内核的内存,malloc分配的是用户的内存
- kmalloc保证分配的内存在物理上是连续的,vmalloc保证的是在虚拟地址空间上的连续,malloc不保证任何东西(猜测的,不一定正确)
- kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相对较大
- 内存只有在要被DMA访问的时候才需要物理上连续
- vmalloc比kmalloc要慢
- kmalloc()是内核中最常见的内存分配方式,它最终调用伙伴系统的__get_free_pages()函数分配,根据传递给这个函数的flags参数,决定这个函数的分配适合什么场合,如果标志是GFP_KERNEL则仅仅可以用于进程上下文中,如果标志GFP_ATOMIC则可以用于中断上下文或者持有锁的代码段中。
kmalloc返回的线形地址是直接映射的,而且用连续物理页满足分配请求,且内置了最大请求数(2**5=32页)。
- vmalloc优先使用高端物理内存,但性能上会打些折扣。
vmalloc分配的物理页不会被交换出去;
vmalloc返回的虚地址大于(PAGE_OFFSET + SIZEOF(phys memory) + GAP),为VMALLOC_START----VMALLOC_END之间的线形地址;
vmalloc使用的是vmlist链表,与管理用户进程的vm_area_struct要区别,而后者会swapped;
- kmap()是主要用在高端存储器页框的内核映射中,一般是这么使用的:
使用alloc_pages()在高端存储器区得到struct page结构,然后调用kmap(struct *page)在内核地址空间PAGE_OFFSET+896M之后的地址空间中(PKMAP_BASE到FIXADDR_STAR)建立永久映射(如果page结构对应的是低端物理内存的页,该函数仅仅返回该页对应的虚拟地址)
kmap()也可能引起睡眠,所以不能用在中断和持有锁的代码中
不过kmap 只能对一个物理页进行分配,所以尽量少用。
对于高端物理内存(896M之后),并没有和内核地址空间建立一一对应的关系(即虚拟地址=物理地址+PAGE_OFFSET这样的关系),所以不能使用get_free_pages()这样的页分配器进行内存的分配,而必须使用alloc_pages()这样的伙伴系统算法的接口得到struct *page结构,然后将其映射到内核地址空间,注意这个时候映射后的地址并非和物理地址相差PAGE_OFFSET.
kmalloc和get_free_page申请的内存位于物理内存映射区域,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因此存在较简单的转换关系。而vmalloc申请的内存则位于vmalloc_start~vmalloc_end之间,与物理地址没有简单的转换关系,虽然在逻辑上它们也是连续的,但是在物理上它们不要求连续。
kmalloc()和vmalloc()介绍
kmalloc()
用于申请较小的、连续的物理内存
1. 以字节为单位进行分配,在<linux/slab.h>中
2. void *kmalloc(size_t size, int flags)分配的内存物理地址上连续,虚拟地址上自然连续
3. gfp_mask标志:什么时候使用哪种标志?如下:
———————————————————————————————-
情形 相应标志
———————————————————————————————-
进程上下文,可以睡眠 GFP_KERNEL
进程上下文,不可以睡眠 GFP_ATOMIC
中断处理程序 GFP_ATOMIC
软中断 GFP_ATOMIC
Tasklet GFP_ATOMIC
用于DMA的内存,可以睡眠 GFP_DMA| GFP_KERNEL
用于DMA的内存,不可以睡眠 GFP_DMA| GFP_ATOMIC
———————————————————————————————-
4. void kfree(const void *ptr)
释放由kmalloc()分配出来的内存块
vmalloc()
用于申请较大的内存空间,虚拟内存是连续的
1. 以字节为单位进行分配,在<linux/vmalloc.h>中
2. void *vmalloc(unsigned long size)分配的内存虚拟地址上连续,物理地址不连续
3.一般情况下,只有硬件设备才需要物理地址连续的内存,因为硬件设备往往存在于MMU之外,根本不了解虚拟地址;但为了性能上的考虑,内核中一般使用kmalloc(),而只有在需要获得大块内存时才使用vmalloc(),例如当模块被动态加载到内核当中时,就把模块装载到由vmalloc()分配 的内存上。
4.void vfree(void *addr),这个函数可以睡眠,因此不能从中断上下文调用。
malloc(), vmalloc()和kmalloc()区别
[*]kmalloc和vmalloc是分配的是内核的内存,malloc分配的是用户的内存
[*]kmalloc保证分配的内存在物理上是连续的,vmalloc保证的是在虚拟地址空间上的连续,malloc不保证任何东西(这点是自己猜测的,不一定正确)
[*]kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相对较大
[*]内存只有在要被DMA访问的时候才需要物理上连续
[*]vmalloc比kmalloc要慢