linux的内存多种创建方式

一、物理内存的管理

Linux对于物理内存的定义有三个方面的概念:内存节点、内存区域和内存页。

内存节点:

是为了Linux的最大兼容性,将UMA和NUMA结合起来,其中NUMA是多处理器通过链表串联起来

内存区域(zone):

考虑到系统的各个模块对分配的物理内存有不同的要求,比如:32位的X86架构下的DMA只能访问16MB的物理内存空间,因此Linux将每个内存节点管理的物理内存划分为不同的区域。三个大的范围:(ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM)

内存页:

内存页是物理内存管理的在最小单位,有时也叫页帧。这是一个struct page的一个结构体对象,系统用一个struct page *mem_mp来存放所有的物理页的struct page的对象指针。其中页的大小取决于MMU的,它将虚拟地址准换成物理地址。


二、调用的函数

对于页的分配函数有alloc_pages和__get_free_pages,而这两个函数最终都是调用alloc_pages_node这个函数,其中__get_free_pages()不能在ZONE_HIGHMEM中分配内存。其中在我们分配内存需要掩码去判断我们去哪个部分分配空间而且有哪些其他的功能
#define __GFP_WAIT	((__force gfp_t)0x10u)	/* Can wait and reschedule? */
#define __GFP_HIGH	((__force gfp_t)0x20u)	/* Should access emergency pools? */
#define __GFP_IO	((__force gfp_t)0x40u)	/* Can start physical IO? */
#define __GFP_FS	((__force gfp_t)0x80u)	/* Can call down to low-level FS? */
#define __GFP_COLD	((__force gfp_t)0x100u)	/* Cache-cold page required */
#define __GFP_NOWARN	((__force gfp_t)0x200u)	/* Suppress page allocation failure warning */
#define __GFP_REPEAT	((__force gfp_t)0x400u)	/* See above */
#define __GFP_NOFAIL	((__force gfp_t)0x800u)	/* See above */
#define __GFP_NORETRY	((__force gfp_t)0x1000u)/* See above */
#define __GFP_COMP	((__force gfp_t)0x4000u)/* Add compound page metadata */
#define __GFP_ZERO	((__force gfp_t)0x8000u)/* Return zeroed page on success */
#define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */
#define __GFP_HARDWALL   ((__force gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */
#define __GFP_THISNODE	((__force gfp_t)0x40000u)/* No fallback, no policies */
#define __GFP_RECLAIMABLE ((__force gfp_t)0x80000u) /* Page is reclaimable */

我们平常调用的kmalloc、vmalloc和kzalloc等等...其中的gfp_t就是由上面的宏组合而成。
#define GFP_ATOMIC	(__GFP_HIGH)
#define GFP_NOIO	(__GFP_WAIT)
#define GFP_NOFS	(__GFP_WAIT | __GFP_IO)
#define GFP_KERNEL	(__GFP_WAIT | __GFP_IO | __GFP_FS)
#define GFP_USER	(__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL)
#define GFP_HIGHUSER	(__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | \ __GFP_HIGHMEM)

其中alloc_pages(gfp_mask,order)定义是
#define alloc_pages(gfp_mask, order) \
alloc_pages_node(numa_node_id(), gfp_mask, order)
最终调用的是 alloc_pages_node(numa_node_id(), gfp_mask, order)函数去分配2^order次幂的内存页。内存大小为PAGE_SIZE*2^order。

三、实现小型内存分配驱动
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/err.h>
//#include <linux/slab_def.h>	



MODULE_LICENSE("GPL");
MODULE_AUTHOR("TangSirNan");
MODULE_DESCRIPTION("a simple driver...");
MODULE_SUPPORTED_DEVICE("ctv_driver");

//这些都是要分配空间的指针
char *kmem_chr = NULL;
struct kmem_cache *ctv_cache = NULL;
char *ptr = NULL;
char *vtr = NULL;

//这个是需要到时候强制转换类型
unsigned long page_addr;


//模块初始化函数,可以采用字符设备驱动
static int __init ctv_init(void)
{
	//step 1:	如果用的是高速缓存且这块内存需要经常的创建和释放
	//			那么采用的是kmem_cache的调用函数
	ctv_cache = kmem_cache_create("ctv_driver",24,0,0,NULL);
	if(IS_ERR(ctv_cache))
		return PTR_ERR(ctv_cache);

	kmem_chr = (char *)kmem_cache_alloc(ctv_cache,GFP_KERNEL);
	if(IS_ERR(kmem_chr))
	{
		kmem_cache_destroy(ctv_cache);

		return PTR_ERR(kmem_chr);
	}

	memcpy(kmem_chr,"hello,world...",15);
	printk(KERN_INFO "kmem_chr = %s \t address = %p\n",kmem_chr,kmem_chr);

	//step 2:	这是通过kmalloc分配的动态空间内存
	ptr = kmalloc(24,GFP_KERNEL);
	if(IS_ERR(ptr))
	{
		return PTR_ERR(ptr);
	}

	memcpy(ptr,"hello,world...",15);
	printk(KERN_INFO "ptr = %s \t ptr = %p\n",ptr,ptr);

	//step 3:	这是通过vmalloc进行空间分配,分配的空间很不可靠
	vtr = vmalloc(24);
	if(IS_ERR(vtr))
		return PTR_ERR(vtr);

	memcpy(vtr,"hello,world...",15);
	printk(KERN_INFO "vtr = %s \t vtr = %p\n",vtr,vtr);


	//step 4:	采用分配的页的形式去分配空间 一般所需的空间比较大才会采用此方式 两种方法
	//unsigned long buf;
	//int order = get_order(16*1024);   必须是2的整数次幂
	//buf = get_free_pages(GFP_KERNEL, order);
	page_addr = __get_free_pages(GFP_KERNEL,2);
	if (!page_addr) 
	{
		/*没有足够的内存,你必须处理这种错误! */
		
		return ENOMEM;
	}
 
	memcpy((char *)page_addr,"hello,world...",15);
	printk(KERN_INFO "page_addr = %s \t page_addr = %p\n",(char *)page_addr,page_addr);
	
	return 0;
}

static void __exit ctv_exit(void)
{
	kmem_cache_free(ctv_cache,(void *)kmem_chr);

	kmem_cache_destroy(ctv_cache);

	kfree(ptr);

	vfree(vtr);

	free_pages(page_addr,2);
}


module_init(ctv_init);
module_exit(ctv_exit);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值