内存管理器(十二)kernel内存管理----kmalloc/kfree
前言
上一篇说了页的获取与释放,既然是内核内存管理,内核自然也有自己的一套内存分配与释放函数。go on!
kmalloc( )--分配函数
这个函数是内核中用来分配内存的函数,它和malloc很像,当时这里多了一个flags标记。用它可以获得以字节为单位的一块内核内存。当然如果希望得到以页为单位的内存还是用__get_free_page()吧。
[c]
这里赋上一小段内核注释
/*kmalloc - allocate memory
* @size: how many bytes of memory are required.
* @flags: the type of memory to allocate.
*/
/*简单的说明了两个参数,一个是内存的大小,一个是标识,不知道标识是什么没有关系,一会说*/
static __always_inline void *kmalloc(size_t size, gfp_t flags)
{
if (__builtin_constant_p(size)) {
if (size > KMALLOC_MAX_CACHE_SIZE)
return kmalloc_large(size, flags);
#ifndef CONFIG_SLOB
if (!(flags & GFP_DMA)) {
int index = kmalloc_index(size);
if (!index)
return ZERO_SIZE_PTR;
return kmem_cache_alloc_trace(kmalloc_caches[index],
flags, size);
}
#endif
}
return __kmalloc(size, flags);
}
[/c]
下来说标识吧,一会儿再接着分析这个函数。
gfp_mask标志
其实再上次说页分配的时候也用到这个标识了,但是这里我们详细 说下。
先看下这里的源码注释,这里已经写了一些标识解释了,原则还是用什么学什么。
c]
/* The @flags argument may be one of:
*
* %GFP_USER - Allocate memory on behalf of user. May sleep.
* 为用户空间分配内存,可能会睡眠
* %GFP_KERNEL - Allocate normal kernel ram. May sleep.
* 最普通的分配方式,也可能会睡眠
* %GFP_ATOMIC - Allocation will not sleep. May use emergency pools.
* For example, use this inside interrupt handlers.
* 分配内存但是不会睡眠,可能会用到紧急内存池,例如在中断信号中
* %GFP_HIGHUSER - Allocate pages from high memory.
* 从高端内存页分配内存
* %GFP_NOIO - Do not do any I/O at all while trying to get memory.
* 尝试分配内存的时候不使用任何IO,不做任何页的交换
* %GFP_NOFS - Do not make any fs calls while trying to get memory.
* 尝试分配内存的时候不使用任何文件系统相关的操作
* %GFP_NOWAIT - Allocation will not sleep.
* 也是在不能中断的时候分配内存,但是不使用紧急内存池,所以失败的概率较大
* %__GFP_THISNODE - Allocate node-local memory only.
* 从本地内存空闲链表节点分配
* %GFP_DMA - Allocation suitable for DMA.
* Should only be used for kmalloc() caches. Otherwise, use a
* slab created with SLAB_DMA.
* 从DMA分配区开始分配内存,但是一般只有在分配高速缓存的时候才使用,毕竟直接寻址的区域并不大,为了保证效率
*(个人觉得Linux两大特点1:一切皆文件。 2:效率第一)
* Also it is possible to set different flags by OR'ing
* in one or more of the following additional @flags:
*
* %__GFP_COLD - Request cache-cold pages instead of
* trying to return cache-warm pages.
* 分配器应当使用高速缓存中的冷页(不经常使用的页)分配
* %__GFP_HIGH - This allocation has high priority and may use emergency pools.
* 高优先等级,很可能使用紧急内存池
* %__GFP_NOFAIL - Indicate (表明)that this allocation is in no way allowed to fail
* (think twice before using).
* 表明这里的分配不能失败,所以会持续进行
* %__GFP_NORETRY - If memory is not immediately (立即)available(可用)(,
* then give up at once.
* 如果没有分配到立即可用的内存就立刻放弃,只尝试分配一次
* %__GFP_NOWARN - If allocation fails, don't issue any warnings.
* 如果分配失败不要展示任何警告信息
* %__GFP_REPEAT - If allocation fails initially, try once more before failing.
* 如果第一次分配失败,尝试下一次分配
* There are other flags available as well, but these are not intended
* for general use, and so are not documented here. For a full list of
* potential flags, always refer to linux/gfp.h.
*/
/*这里还注释了几句,这里的标识并不是完全的标识,所有的标识都在(linux/gfp.h)
[/c]
因为kmalloc 牵扯到slab 缓存机制,暂且浅尝辄止,等后续明白了slab 之后再来看具体实现
kfree( )
这是一些释放的函数。
[c]
/*
* Common kmalloc functions provided by all allocators
*/
void * __must_check __krealloc(const void *, size_t, gfp_t);
void * __must_check krealloc(const void *, size_t, gfp_t);
void kfree(const void *);
void kzfree(const void *);
size_t ksize(const void *);
[/c]
源代码中提供了很多,这个阶段我们只要会用就OK
这就想当与我们glibc 中的free 函数很类似,今天暂且不详细说,后边会分析源码的。
如果分配的空间不是kmalloc()分配的,我们一定不能使用这个函数释放,这将会导致严重的后果,但是这里调用free(NULL)确实安全的。
说了这么多,写个内核模块玩玩,全当消遣
[c]
#include<linux/module.h>
#include<linux/mm_types.h>
#include<linux/gfp.h>
#include<linux/mm.h>
#include<linux/slab.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zmrlinux");
MODULE_DESCRIPTION("something about kmalloc");
static int __init KMALLOC(void){
char *temp;
printk("I want to malloc \n");
temp = (char *)kmalloc(sizeof(char) * 100,GFP_KERNEL);
if(NULL == temp){
printk("ERROR:alloc failed\n");
return -1;
}else{
printk("I malloc is OK\n");
}
kfree(temp);
return 0;
}
static void __exit KMALLOC_out(void){
printk("GOODBYE \n");
}
module_init(KMALLOC);
module_exit(KMALLOC_out);
/*Makfile*/
obj-m := page_malloc.o
CURRENT_PATH := ${shell pwd}
CURRENT_KERNEL_PATH := ${shell uname -r}
LINUX_KERNEL_PATH := /usr/src/kernels/$(CURRENT_KERNEL_PATH)
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
rm *.o rm *.ko
[/c]
OK !Done!!