当设备长时间运行后,内存碎片化,很难找到连续的物理页。在这种情况下,如果需要分配长度超过一页的内存块,可以使用不连续页分配器,分配虚拟地址连续但是物理地址不连续的内存块。在 32 位系统中不连分配器还有一个好处:优先从高端内存区域分配页,保留稀缺的低端内存区域。
vmalloc:分配不连续的物理地址空间,但虚拟内存地址是连续的。
vfree:配套,释放 vmalloc 分配的内存地址。
kmalloc:分配物理连续的内存地址(则虚拟地址自然连续,基于 slab)。
kfree:配套,释放 kmalloc 分配的内存地址。
struct vm_struct {
struct vm_struct *next;
void *addr;
unsigned long size;
unsigned long flags;
struct page **pages;
unsigned int nr_pages;
phys_addr_t phys_addr;
const void *caller;
};
struct vmap_area {
unsigned long va_start;
unsigned long va_end;
struct rb_node rb_node; /* address sorted rbtree */
struct list_head list; /* address sorted list */
/*
* The following three variables can be packed, because
* a vmap_area object is always one of the three states:
* 1) in "free" tree (root is vmap_area_root)
* 2) in "busy" tree (root is free_vmap_area_root)
* 3) in purge list (head is vmap_purge_list)
*/
union {
unsigned long subtree_max_size; /* in "free" tree */
struct vm_struct *vm; /* in "busy" tree */
struct llist_node purge_list; /* in purge list */
};
};
分配不连续的物理地址空间,但虚拟内存地址是连续的。
vmtest.c
/* 头文件和全局变量地声明*/
#include
#include
#include
static int __init vmalloc_InitFunc(void);
static void __exit vmalloc_ExitFunc(void);
#define MEMORY_SIZE 4096
char * pmymemory;
// 模块初始化函数
int __init vmalloc_InitFunc(void)
{
pmymemory = (char *)vmalloc(MEMORY_SIZE);
if(pmymemory == NULL )
printk("执行:vmalloc(...)函数分配内存失败! \n");
else
printk("执行:vmalloc(...)函数成功,地址 = 0x%lx\n", (unsigned long)pmymemory);
return 0;
}
// 模块退出函数
void __exit vmalloc_ExitFunc(void)
{
if(NULL != pmymemory)
{
vfree(pmymemory);
printk("调用:vfree(...)释放内存成功!\n");
}
printk("正常:内核模块退出成功!\n");
}
/* 模块初始化操作和退出函数调用 */
module_init(vmalloc_InitFunc);
module_exit(vmalloc_ExitFunc);
MODULE_LICENSE("GPL"); /* 描述模块代码接受的软件许可协议 */
MODULE_AUTHOR("Lion Long"); /* 描述模块的作者信息:包括作者姓名及邮箱等等 */
MODULE_DESCRIPTION(" kernel module : vmalloc/vfree"); /* 简要描述此模块用途及功能介绍*/
Makefile
obj-m:=vmtest.o
CURRENT_PAHT:=$(shell pwd)
LINUX_KERNEL:=$(shell uname -r)
LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) cleals
(1)make。
$ make
make -C /usr/src/linux-headers-4.15.0-142-generic M=/home/fly/workspace/vmalloctest modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-142-generic'
CC [M] /home/fly/workspace/vmalloctest/vmtest.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/fly/workspace/vmalloctest/vmtest.mod.o
LD [M] /home/fly/workspace/vmalloctest/vmtest.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-142-generic'
$ ls
Makefile modules.order Module.symvers vmtest.c vmtest.ko vmtest.mod.c vmtest.mod.o vmtest.o
(2)插入模块。
# insmod vmtest.ko
# dmesg -c
[159699.561428] 执行:vmalloc(...)函数成功,地址 = 0xffffa6aec0668000
分配物理连续的内存地址(则虚拟地址自然连续,基于 slab)。
kmtest.c
/* 头文件和全局变量地声明*/
#include
#include
#include
#include
static int __init kmalloc_InitFunc(void);
static void __exit kmalloc_ExitFunc(void);
#define MEMORY_SIZE 4096
char * pmymemory;
// 模块初始化函数
int __init kmalloc_InitFunc(void)
{
pmymemory = (char *)kmalloc(MEMORY_SIZE,GFP_KERNEL);
if(pmymemory == NULL )
printk("执行:kmalloc(...)函数分配内存失败! \n");
else
{
// /*输出分配的内存空间的起始地址*/
printk("执行:kmalloc(...)函数成功,地址 = 0x%lx\n", (unsigned long)pmymemory);
}
return 0;
}
// 模块退出函数
void __exit kmalloc_ExitFunc(void)
{
if(NULL != pmymemory)
{
kfree(pmymemory);
printk("调用:kfree(...)释放内存成功!\n");
}
printk("正常:内核模块退出成功!\n");
}
/* 模块初始化操作和退出函数调用 */
module_init(kmalloc_InitFunc);
module_exit(kmalloc_ExitFunc);
MODULE_LICENSE("GPL"); /* 描述模块代码接受的软件许可协议 */
MODULE_AUTHOR("Lingshengedu"); /* 描述模块的作者信息:包括作者姓名及邮箱等等 */
MODULE_DESCRIPTION(" kernel module : kmalloc/kfree"); /* 简要描述此模块用途及功能介绍*/
Makefile
obj-m:=kmkf.o
CURRENT_PAHT:=$(shell pwd)
LINUX_KERNEL:=$(shell uname -r)
LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) cleals
(1)make。
# make
make -C /usr/src/linux-headers-4.15.0-142-generic M=/home/fly/workspace/kmalloctest modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-142-generic'
CC [M] /home/fly/workspace/kmalloctest/kmtest.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/fly/workspace/kmalloctest/kmtest.mod.o
LD [M] /home/fly/workspace/kmalloctest/kmtest.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-142-generic'
# ls
kmtest.c kmtest.ko kmtest.mod.c kmtest.mod.o kmtest.o Makefile modules.order Module.symvers
(2)insmod。
# insmod kmtest.ko
# dmesg -c
[160514.302923] 执行:kmalloc(...)函数成功,地址 = 0xffff8f54b28ac000