2020-05-23
关键字:kmalloc、kzalloc、kcalloc
1、kmalloc()
kmalloc() 是Linux内核开发中最常使用的申请内存的函数。它的原型如下所示:
#include <linux/slab.h> void *kmalloc(size_t size, int flags);
函数的返回值通常就指向所申请到的内存空间的起始地址。当然,有时它也会指向 NULL--如果内存的申请出于某些原因失败的话。
参数 1 表示要申请的空间大小,单位是字节。size_t 其实就是个 unsigned int 的别名。
参数 2 表示申请内存时的模式。这个模式有很多个可选类型,它们均声明于 <linux/gfp.h> 中。虽然在 gfp.h 中有众多可选类型,但其实最常用的也就两个值:
1、GFP_KERNEL
这个标志表示当内核中的可用内存不足时,调用者,即发起当前申请请求的进程将会被强制进入休眠状态以等待有足够的内存可供申请为止。也正因为这个标志有可能导致调用进程的休眠,这个标志只被允许在“进程上下文”中使用。“中断上下文”如果要休眠的话是会引发错误的。
2、GFP_ATOMIC
内核会额外地将一部分内存划分出来以专供于原子性的空间申请使用。简单来说,使用这个标志就是有内存时就给你分配,没有就直接以失败告终,它不会让你的进程进入休眠态的。
需要注意的是:以上的头文件贴出的仅仅是标准Linux内核中的声明。不同版本、用途的Linux内核可能会有不同的声明结构,这些需要各位同学自行确认。
以下是一个使用 kmalloc() 函数申请内存的小实例:
struct Person{ char *name; int age; }; int __init m_init() { struct Person *p = (struct Person *)kmalloc(sizeof(struct Person), GFP_KERNEL); return 0; }
2、kzalloc()
kzalloc()函数其实不需要介绍。因为它在本质上就是 kmalloc() 函数,只不过多了一个自动帮我们把所申请到的内存清零的操作而已。
我们直接看一下这个函数的原型声明就了然了。这个函数位于 <linux/slab.h> 头文件中:
/** * kzalloc - allocate memory. The memory is set to zero. * @size: how many bytes of memory are required. * @flags: the type of memory to allocate (see kmalloc). */ static inline void *kzalloc(size_t size, gfp_t flags) { return kmalloc(size, flags | __GFP_ZERO); }
既然如此,kzalloc() 的示例代码就没有必要贴了。
3、kcalloc()
kcalloc()函数的本质也是 kmalloc() 函数。它相较于 kzalloc() 函数又多了一层“数量”的封装。闲话少说,直接看下它的原型:
/** * kcalloc - allocate memory for an array. The memory is set to zero. * @n: number of elements. * @size: element size. * @flags: the type of memory to allocate (see kmalloc). */ static inline void *kcalloc(size_t n, size_t size, gfp_t flags) { return kmalloc_array(n, size, flags | __GFP_ZERO); }
kmalloc_array()函数的原型如下:
static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags) { if (size != 0 && n > SIZE_MAX / size) return NULL; return __kmalloc(n * size, flags); }
绕了一圈,又是 kmalloc() 的封装。既然如此,就没有贴示例代码的必要了。
4、空间的释放
前面贴了三种内存空间申请的函数,它们在本质上都是同一个函数 kmalloc() 的封装。
因此,通常来说,要释放申请的内存都可以用同一个函数来完成:
#incclude <linux/slab.h> void kfree(const void *);