参考:《linux设备驱动开发详解》华清远见 ,--人民邮电出版社
用户空间内存动态申请
在用户空间动态申请内存的函数为 malloc(),这个函数在各种操作系统上的使用是一致的,malloc()申请的内存的释放函数为 free()。malloc()的内存一定要被 free(),否则会造成内存泄漏。理想情况下,malloc()和 free()应成对出现,即谁申请,就由谁释放。
void *malloc(unsigned int num_bytes); /* 函数原型 */
void free(void *ptr);
char *func(void)
{
char *p;
p = malloc(...);
if(p == NULL)
{
...
}
free(p);
}
内核空间动态申请内存
问题:
- 有哪些函数可以动态申请内存?
- 这些动态申请内存函数之间有什么区别?
在 Linux 内核空间申请内存涉及的函数主要包括 kmalloc()、_ _get_free_pages()和vmalloc()等。kmalloc()和_ _get_free_pages()(及其类似函数)申请的内存位于物理内存映射区域,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因此存在较简单的转换关系。而 vmalloc()在虚拟内存空间给出一块连续的内存区,实质上,这片连续的虚拟内存在物理内存中不一定连续,而 vmalloc()申请的虚拟内存和物理内存之间也没有简单的换算关系。
1.kmalloc()
void *kmalloc(size_t size, gfp_t flags);
参数:
- 分配的块的大小
- 分配标志,用于控制kmalloc的行为,一般为GFP_KERNEL,代表优先权。
kmalloc()的底层依赖_ _get_free_pages()实现,分配标志的前缀 GFP 正好是这个底层函数的缩写。使用 GFP_ KERNEL 标志申请内存时,若暂时不能满足,则进程会睡眠等待页,即会引起阻塞,因此不能在中断上下文或持有自旋锁的时候使GFP_KERNE 申请内存。
gfp_mask标志:1.行为修饰符 2.区修饰符 3.类型 一一《linux内核设计与实现——第三版——中文版》P192
进行上下文,可以睡眠 | GFP_KERNEL |
进行上下文,不可以睡眠 | GFP_ATOMIC |
中断处理程序 | GFP_ATOMIC |
软中断 | GFP_ATOMIC |
tasklet | GFP_ATOMIC |
需要用于DMA的内存,可以睡眠 | (GFP_DMA|GFP_KERNEL) |
需要用于DMA的内存,不可以睡眠 | (GFP_DMA|GFP_ATOMIC) |
2.__get_free_pages ()
_ _get_free_pages()系列函数/宏是 kmalloc()实现的基础,_ _get_free_pages()系列函数/宏包括 get_zeroed_page()、__get_free_page()和_ _get_free_pages()。
get_zeroed_page(unsigned int flags); //该函数返回一个指向新页的指针并且将该页清零。
__get_free_page(unsigned int flags); //该宏返回一个指向新页的指针但是该页不清零,它实际上为:
#define __get_free_page(gfp_mask) \
__get_free_pages((gfp_mask),0) //就是调用了下面的
__get_free_pages() //申请 1 页。
__get_free_pages(unsigned int flags, unsigned int order);
/*该函数可分配多个页并返回分配内存的首地址,分配的页数为 2order,分配的页也不清零。order 允许的最大值是 10(即 1024 页)或者 11(即2048 页),依赖于具体的硬件平台。*/
使用_ _get_free_pages()系列函数/宏申请的内存应使用下列函数释放:
void free_page(unsigned long addr);
void free_pages(unsigned long addr, unsigned long order);
3.vmalloc()
vmalloc()一般用在为只存在于软件中(没有对应的硬件意义)的较大的顺序缓冲区分配内存,vmalloc()远大于__get_free_pages()的开销,为了完成 vmalloc(),新的页表需要被建立。因此,只是调用 vmalloc()来分配少量的内存(如 1 页)是不妥的。
vmalloc()申请的内存应使用 vfree()释放,vmalloc()和 vfree()的函数原型如下:
void *vmalloc(unsigned long size);
void vfree(void * addr);