Linux内核态动态内存分配与释放​

kmalloc用云内核里进行分配内存。

语法: ​​void *kmalloc(size_t size, int flags);​

(1)size要分配内存的大小。以字节为单位。

(2)flags要分配内存的类型。

在设备驱动程序或者内核模块中动态开辟内存,不是用malloc,而是kmalloc ,vmalloc,或者用get_free_pages直接申请页。释放内存用的是kfree,vfree,或free_pages.。

kmalloc函数返回的是虚拟地址(线性地址). kmalloc特殊之处在于它分配的内存是物理上连续的,这对于要进行DMA的设备十分重要. 而用vmalloc分配的内存只是线性地址连续,物理地址不一定连续,不能直接用于DMA。

kmalloc() 分配连续的物理地址,用于小内存分配。get_free_page() 分配连续的物理地址,用于整页分配。kmalloc() 函数本身是基于 slab 实现的。slab 是为分配小内存提供的一种高效机制。但 slab 这种分配机制又不是独立的,它本身也是在页分配器的基础上来划分更细粒度的内存供调用者使用。也就是说系统先用页分配器分配以页为最小单位的连续物理地址,然后 kmalloc() 再在这上面根据调用者的需要进行切分。 kmalloc() 的实现,kmalloc()函数的实现是在 __do_kmalloc() 中,可以看到在 __do_kmalloc()代码里最终调用了 __cache_alloc() 来分配一个 slab,其实kmem_cache_alloc() 等函数的实现也是调用了这个函数来分配新的 slab。我们按照 __cache_alloc()函数的调用路径一直跟踪下去会发 cache_grow() 函数中使用了 kmem_getpages()函数来分配一个物理页面,kmem_getpages() 函数中调用的alloc_pages_node() 最终是使用 __alloc_pages() 来返回一个struct page 结构,而这个结构正是系统用来描述物理页面的。这样也就证实了上面所说的,slab 是在物理页面基础上实现的。kmalloc() 分配的是物理地址。

1.1 kmalloc函数

Kmalloc分配的是连续的物理地址空间。申请的空间大小一般为128KB

头文件:#include <linux/slab.h>

1.1.1 申请空间

static void *kmalloc(size_t size, gfp_t flags)

参数:

size_t size :申请的空间大小

gfp_t flags:申请的标志(模式)​

返回值:申请的空间首地址。如果为NULL,表示分配失败!​

一般填写的模式:

GFP_ATOMIC:用来从中断处理和进程上下文之外的其他代码中分配内存,分配内存优先级高,不会阻塞

GFP_KERNEL:内核内存的正常分配方式,可能会阻塞。

1.1.2 释放内存空间

void kfree(const void *block)

参数:

void *block:将要释放空间的首地址

1.1.3 示例

#include <linux/init.h>

#include <linux/module.h>

#include <linux/slab.h>

char *buff;

static int __init interrupt_init(void)

{

printk("init okn");

申请空间*/

buff=kmalloc(1024, GFP_KERNEL);

初始化空间*/

memset(buff,0x10,1024);

打印出空间的数据*/

int i;

for(i=0;i<1024;i++)

{

printk("0x%X n",buff[i]);

}

return 0;

}

static void __exit interrupt_exit(void)

{

释放申请的空间*/

kfree(buff);

printk("exit okn");

}

module_init(interrupt_init); /*驱动入口*/

module_exit(interrupt_exit); /*驱动出口*/

MODULE_LICENSE("GPL");

1.2 vmalloc 函数

分配的空间是线性的,在物理地址上不连续!最多分配1GB的空间。

定义文件:mmvmalloc.c

头文件:#include <linux/vmalloc.h>

1.2.1 申请空间

void *vmalloc(unsigned long size)

参数:

unsigned long size :分配空间的大小

返回值:申请的空间首地址

1.2.2 释放空间

void vfree(const void *addr)

参数:

const void *addr:释放的空间首地址

1.3 示例代码1

#include <linux/init.h>
#include <linux/module.h>

#include <linux/slab.h>
char *buff;
static int __init interrupt_init(void)
{
printk("init okn");
/*1.1 申请空间*/
buff=kmalloc(1024, GFP_KERNEL);

/*1.2 初始化空间*/
memset(buff,0x10,1024);

/*1.3 打印出空间的数据*/
int i;
for(i=0;i<1024;i++)
{
printk("0x%X n",buff[i]);
}
return 0;
}

static void __exit interrupt_exit(void)
{
/*释放申请的空间*/
kfree(buff);
printk("exit okn");
}

module_init(interrupt_init); /*驱动入口*/
module_exit(interrupt_exit); /*驱动出口*/
MODULE_LICENSE("GPL");

1.4 示例代码2

#include <linux/init.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
char *buff=NULL;
static int __init interrupt_init(void)
{
printk("init okn");
/*1.1 申请空间*/
buff=vmalloc(1024);

if(buff==NULL)
{
printk("内存空间分配失败!nn");
}

/*1.2 初始化空间*/
memset(buff,0x10,1024);

/*1.3 打印出空间的数据*/
int i;
for(i=0;i<1024;i++)
{
printk("0x%X n",buff[i]);
}
return 0;
}

static void __exit interrupt_exit(void)
{
/*释放申请的空间*/
vfree(buff);
printk("exit okn");
}

module_init(interrupt_init); /*驱动入口*/
module_exit(interrupt_exit); /*驱动出口*/
MODULE_LICENSE("GPL");

发表评论

相关文章