Linux内存管理之slab 2:slab API

slab原理及相关参考之前的博客
Linux内存管理之slab 1:slab原理
https://blog.csdn.net/lqy971966/article/details/112980005

0. 前沿/须知:

kmem_cache: 内存池
slab:       内存池从系统申请内存的基本单位
object:     内存池提供的内存的单位

1. kmem_cache_create

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

功能:

创建一个slab新缓存

参数:

name:缓存的名称(用来生成kmem_cache的名字),会在/proc/slabinfo中出现
size:对象的大小,以字节为单位,若此处填写过小的size(比如sizeof(int))会出现死机的问题
align:每个对象的对齐,一般使用0就可以;
flags:创建kmem_cache标识位掩码,使用0,表示默认;
	分配缓存时的选项如下
		SLAB_RED_ZONE 在对象头 尾插入标志,探测缓冲越界
		SLAB_POISON 使用slab层已知的值填充slab,有利于对未初始化内存的访问
		SLAB_CACHE_DMA 每个数据对象在 DMA 内存区段分配.
		SLAB_HWCACHE_ALIGN 命令slab层把一个slab内的所有对象按高速缓存行对齐。
		SLAB_PANIC 这个标志当分配失败时提醒slab层
		SLAB_STORE_USER:用struct track存储最后一个进程信息
ctor: 高速缓存的构造函数
头文件:#include <linux/slab.h>

返回值:

从 cache_cache 中返回一个指向 kmem_cache 实例的*cachep指针;
当然该 kmem_cache 对象也会被加入 cache_chain 链表中;	

1.1 kmem_cache_create (仅分配一个kmem_cache实例)未分配实际物理页

kmem_cache_create()仅仅是从cache_cache中分配一个kmem_cache实例,并不会分配实际的物理页,当然也就没有slab了(也没有对象)

1.2 slab 创建流程

那什么时候会创建一个slab呢?
只有满足下面两个条件时,才会给 kmem_cache 分配Slab:

(1)已发出一个分配新对象的请求;
(2)kmem_cache 中没有了空闲对象;

其实本质就是:
需要得到该 kmem_cache 下一个对象,而kmem_cache没有空闲对象,这时候就会给kmem_cache分配一个slab了。
所以新分配的kmem_cache只有被要求分配一个对象时,才会调用函数去申请物理页;

具体的分配流程:

首先会调用 kmem_cache_grow()函数给kmem_cache分配一个新的Slab。
其中,该函数调用kmem_gatepages()从伙伴系统获得一组连续的物理页面
然后又调用kmem_cache_slabgmt()获得一个新的Slab结构
还要调用kmem_cache_init_objs()为新Slab中的所有对象申请构造方法
最后,调用kmem_slab_link_end()把这个Slab结构插入到缓冲区中Slab链表的末尾

1.3 slab 与伙伴系统

从slab的分配可以知道,其实所有的内存最终还是要伙伴系统来分配,这里就可以知道,这些内存都是连续的物理页。

在某些情况下内核模块可能需要频繁的分配和释放相同的内存对象,这时候slab可以作为内核对象的缓存,当slab对象被释放时,slab分配器并不会把对象占用的物理空间还给伙伴系统。这样的好处是当内核模块需要再次分配内存对象时,不需要那么麻烦的向伙伴系统申请,而是可以直接在slab链表中分配一个合适的对象

2. kmem_cache_alloc

void *kmem_cache_alloc(struct kmem_cache *cachep,gfp_t flags)

功能:

从一个给定的缓存分配一个对象

参数:

cachep:kmem_cache 结构指针(kmem_cache_create 返回的对象)
flags: 分配标志选项 如 GFP_KERNEL GFP_ATOMIC
	GFP_KERNEL :从内核 RAM 中分配内存(这个调用可能会睡眠)。
	GFP_ATOMIC :使该调用强制处于非睡眠状态(对中断处理程序非常有用)。

2.1 kmem_cache_create 和 kmem_cache_alloc 关系

kmem_cache_create()只是分配size大小的缓存,并不会调用对象的构造函数,只有当再调用 kmem_cache_alloc()时才会构造对象;
另外调用 kmem_cache_create()并没有分配slab,是在创建对象的时候发现没有空闲对象,调用cache_grow()分配一个slab,然后再分配对象。

2.2 kmalloc 函数本质

kmalloc 是循环遍历可用缓存来查找可以满足大小限制的缓存。
找到之后,就(使用 kmem_cache_alloc )分配一个对象。

void * kmalloc(size_t size, int flags)
{
	struct cache_size *csizep = malloc_sizes; //1. 定义好大小的数组
	struct kmem_cache *cachep;

	/* 2. 这是关键,从 malloc_sizes 数组(其实也是从kmem_cache链表)中遍历,
	   得到地一个大于等于size的cache */
	while(size > csizep->cs_size)
		csizep++;

	cachep = csizep->cs_cachep;
	
	// 3.这里会发现正真分配对象的还是靠 kmem_cache_alloc()函数
	return kmem_cache_alloc(cachep, flags)
}

2.3 kfree 函数本质

kfree调用 kmem_cache_free(下面4) 调用中使用该引用释放对象

3. kmem_cache_zalloc (zero 清零)

内核函数 kmem_cache_zalloc 与 kmem_cache_alloc 类似,只不过它对对象执行 memset 操作,用来在将对象返回调用者之前对其进行清除操作。

static inline void *kmem_cache_zalloc(struct kmem_cache *k, gfp_t flags)

功能:

内部调用了 kmem_cache_alloc 传递的标志多了个 __GFP_ZERO 对分配的对象进行清零

参数:

k:kmem_cache结构指针
flags:分配标志选项 如 GFP_KERNEL GFP_ATOMIC

3.1 kmem_cache_zalloc 内核实现

static inline void *kmem_cache_zalloc(struct kmem_cache *k, gfp_t flags)
{
	return kmem_cache_alloc(k, flags | __GFP_ZERO);
}

4. kmem_cache_free

要将一个对象释放回 slab

void kmem_cache_free(struct kmem_cache *cachep, void *objp)

功能:

释放从缓存中分配的对象,释放回slab

参数:

cachep:kmem_cache 缓存指针
objp:从缓存中分配的对象

5. kmem_cache_destroy

void kmem_cache_destroy(struct kmem_cache *cachep)

功能:

销毁一个缓存
在调用这个函数时,缓存必须为空。

参数:

cachep:用 kmem_cache_create 创建的缓存对象

参考:
https://blog.csdn.net/yldfree/article/details/81185652
https://zhuanlan.zhihu.com/p/51660182
https://blog.csdn.net/yuzhihui_no1/article/details/47305361
https://blog.csdn.net/yuzhihui_no1/article/details/47284329

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值