linux驱动之内存分配kmalloc

内存管理是操作系统的一个重要的处理方向,相对于android和ios来讲,这个可能就是导致为什么ios的操作系统在1GB的内存上实际使用起来要优于android的2GB甚至是3GB。

ios起源于unix,而linux也起源于unix,可以说是师从同门,ios重视桌面化系统,而linux则在服务器一端是佼佼者,假如linux能够发力,将linux版的系统直接运行在手机上,那恐怕也依然流畅无比。

对于我一个搞机的工程师来讲,真心希望那一天不管是ubuntu,还是redhat,能够成为手机系统的主流,这样ios也无需吹嘘他的系统有多流畅,有多稳定,毕竟,linux也是服务器中非常稳定的,毕竟处理的事务不是和手机一个数量级的。

不过话说,我也想买一个ios看看,不对,我有ipad,买了将近8个月了,重启了一次,TP失灵了,其他的时候也卡,但90%的时候是非常好的。

好了,废话不说了。进入正题。

学过linux程序设计的时候,都会有讲到malloc的程序,申请内存,释放内存,内存泄漏。linux系统内核中也有这样的东西

kmalloc

void *kmalloc(size_t size, gfp_t flags)  (linux/slab.h)

那么第一个参数是申请的大小,flags是标志,前一个参数没有什么介绍的,第二个参数是控制kmalloc的行为的。那么具体看一下flags的enum

typedef enum {
	GFP_KERNEL,
	GFP_ATOMIC,
	__GFP_HIGHMEM,
	__GFP_HIGH
} gfp_t;
常用的是GFP_KERNEL,它总是调用get-free_pages的函数来申请内存区域(linux设备驱动)。 但是这个会导致休眠的行为,例如在tasklet中我们是不允许调用有睡眠可能的函数的。

当我们在不允许休眠的进程中,我们要使用GFP_ATOMIC。其他的有和平台相关的,就不具体介绍了。

特别注意:使用kmalloc的时候并不将申请的内存清空,意思就是不初始化,假如我们使用的时候不经意间申请了一块内存,而内存中存在一些敏感的信息,我们没有对内存区域重写,直接访问的时候会导致异常,甚至将信息泄漏。

所以就有一个函数应运而生了

/**
 * 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);
}
ok,看到了吗,申请的同时将内存的清空成0了,所以我建议使用kzalloc的函数,省的你忘记了对申请空间清0.

后备高速缓存(lookaside cache)

有些内存有时候我们需要不停的申请,释放,申请,释放,所谓的内存碎片有可能产生哦,所以内核中就有这样的特殊的内存区域,就是特殊的内存池。一般的驱动是不会这样重复的申请内存以及释放内存的。但是有一类的设备可能需要的,热插拔的USB设备。当USB插入时,申请空间,维护一个对于这个USB的空间,当USB时,我们是没有必要在保留的,所以释放。所以这个后备高速缓存其实还是有用的,即存在即道理。

struct kmem_cache *
kmem_cache_create(const char *name, size_t size, size_t align,
 unsigned long flags, void (*ctor)(void *))

struct kmem_cache *
kmem_cache_create(const char *name, size_t size, size_t align,
		  unsigned long flags, void (*ctor)(void *))
{
	return kmem_cache_create_memcg(NULL, name, size, align, flags, ctor, NULL);
}
参数的含义:

@1:name: 字符型的字串

@2:size :申请的空间大小

@3:align:这是对齐的选项,但是一般不做特殊处理,一般传递0

@4:flags:

#define SLAB_DEBUG_FREE		0x00000100UL	/* DEBUG: Perform (expensive) checks on free */
#define SLAB_RED_ZONE		0x00000400UL	/* DEBUG: Red zone objs in a cache */
#define SLAB_POISON		0x00000800UL	/* DEBUG: Poison objects */
#define SLAB_HWCACHE_ALIGN	0x00002000UL	/* Align objs on cache lines */
#define SLAB_CACHE_DMA		0x00004000UL	/* Use GFP_DMA memory */
#define SLAB_STORE_USER		0x00010000UL	/* DEBUG: Store the last owner for bug hunting */
#define SLAB_PANIC		0x00040000UL	/* Panic if kmem_cache_create() fails */
常用的是SLAB_HWCACHE_ALIGN

@5:构造函数:当分配一组对象内存时调用的。


分配内存空间:void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)

void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
{
	void *ret = slab_alloc(s, gfpflags, _RET_IP_);


	trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size, s->size, gfpflags);


	return ret;
}


其中s是我们用kmem_cache_create调用返回的结果,gfpflags是调用kmalloc时的标志位

typedef enum {
	GFP_KERNEL,
	GFP_ATOMIC,
	__GFP_HIGHMEM,
	__GFP_HIGH
} gfp_t;

关于这些标志位,上面的kmalloc有提到的。一般用到的是GFP_KERNEL,当我们遇到不应该休眠的时候,应该使用GFP_ATOMIC。

释放内存对象

void kmem_cache_free(struct kmem_cache *s, void *x),s是kmem_cache_create申请的内存,x是内存的一个对象,就是你申请的其他不想要的空间,当然不可以乱释放。模块卸载是应该采用的是

void kmem_cache_destroy(struct kmem_cache *s),那么s是kmem_cache_create申请的空间。注意要检查返回值。

内存池

有的时候我们的代码是不允许申请空间失败的,所以在linux中有这样的一个机制就是内存池。

mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
mempool_free_t *free_fn, void *pool_data)

/**
 * mempool_create - create a memory pool
 * @min_nr:    the minimum number of elements guaranteed to be
 *             allocated for this pool.
 * @alloc_fn:  user-defined element-allocation function.
 * @free_fn:   user-defined element-freeing function.
 * @pool_data: optional private data available to the user-defined functions.
 *
 * this function creates and allocates a guaranteed size, preallocated
 * memory pool. The pool can be used from the mempool_alloc() and mempool_free()
 * functions. This function might sleep. Both the alloc_fn() and the free_fn()
 * functions might sleep - as long as the mempool_alloc() function is not called
 * from IRQ contexts.
 */
mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
				mempool_free_t *free_fn, void *pool_data)
{
	return mempool_create_node(min_nr,alloc_fn,free_fn, pool_data,
				   GFP_KERNEL, NUMA_NO_NODE);
}

典型的用法:

1.mp = mempool_create(MIN_BUFS, mempool_alloc_slab, mempool_free_slab,
buf_pool_cache);

2.销毁是用:void mempool_destroy(mempool_t *pool)

驱动程序中尽量避免使用这个用法(linux设备驱动)。

其实还有其他的分配内存的办法买这里不再列举,包括我调了很多驱动,什么page函数,vmalloc,都不是怎么太常见,而且在linux设备驱动这本书中也强烈建议不要使用vmalloc,所以可能若干年后,linux代码中都没有这样的东西了,就不再详细分析其使用方法了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值