SLAB分配器
1.综述
用一段话来描述slab。就是讲内存按照对象为单位进行组织,一定数目的对象聚集在一起称为一个slab。系统通过操作slab来进行内存的分配。每个CPU上的per-CPU结构中,保存了空闲的对象指针,通过这些指针,系统可以快速有效的进行对象分配。
上面的图来自PLK中, 很明显,kmem_cache控制了内存节点的slab内存分配。结构中有指向per-CPU缓存的arraycache指针,也有指向slab链表的三个指针。
2.着色原理
所谓的着色,目的只是为了让slab中相同偏移量的对象进入CPUcache的时候,尽量不会出现处在同一cache行中
3.kmem_cache的操作
cache创建
kmem_cache_create.
创建kmem_cache的数据结构,会调用kmem_cache_alloc来创建slab
slab创建
kmem_cache_alloc调用_cache_alloc,最终调用__cache_alloc。__cache_alloc会查看array_cache中是否有空闲的对象,如果有则直接分配,如果没有,就需要重新填写array_cache。
slab销毁
kmem_cache_free
4.kmalloc过程
简单地说,先查找合适的内存对象,在通过__cache_alloc进行对象分配。这里需要分成两种情况,一种情况,当申请的内存大小在编译时确定的话,则直接记进行了编译优化
否则,直接调用__kmalloc进行查找符合大小的cache。
5, vmalloc过程
vmalloc负责申请非连续区域的内存。需要知道的是,vmalloc和Kmalloc都是内核中申请内存的函数,而malloc则是属于用户态的内存申请,由glibc通过系统调用brk,mmap实现。
vmalloc最终会调用到__vmalloc_node,之后则是先通过__get_vm_area_node获取一段虚拟地址区域,然后通过__vmalloc_area_node映射到具体的地址空间上。
该函数首先通过kmalloc申请page管理数据结构的内存,然后通过alloc_page逐个申请内存。
slab分配器 - 实例用法
1.定义一个 kmem_cache 对象,然后对其进行初始化
这里是采用的通用slab缓存方式实现,这个特定的缓存包含 32 字节的对象,并且是硬件缓存对齐的(由标志参数 SLAB_HWCACHE_ALIGN 定义)。
如果采用专用slab缓存,那么必须要知道建立缓存对象的大小,比如,我们需要为sample_struct结构体建立一个专用的slab缓存,那么其调用格式如下:
接下来以专用slab缓存为实例
2.使用所分配的 slab 缓存对象,或释放所分配的 slab 缓存对象
3.slab 缓存的销毁。调用者必须确保在执行销毁操作过程中,不要从缓存中分配对象。
4.所在slab缓存使用过程中,可以通过slabtop查看。
5.实例
插入模块、删除模块前后slabtop观察结果
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1020 100% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1010 99% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1002 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1001 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1000 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1000 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1000 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1000 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1000 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
[root@RedHat ~]#
分析:
a. 再没有插入模块时,没有数据
b. 插入模块时,新建slab,这是数据都是active的,此时对象数目为OBJS = SLABS * OBJ/SLAB = 34*30 = 1020;
c. 随着模块稳定下来, 未使用的对象变为inactive,那么active数目就变味了1000;(与程序相对应)
d. 删除模块后,数据消失