SLUB的引入及举例说明
Posted Loopers
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SLUB的引入及举例说明相关的知识,希望对你有一定的参考价值。
我们都知道Buddy分配器是按照页的单位分配的(Buddy系统分配器实现),如果我们需要分配几十个字节,几百个字节的时候,就需要用到SLAB分配器。
SLAB分配器专门是针对小内存分配而设计的,比如我们驱动中常见的Kmalloc分配器就是通过SLAB分配器分配的内存。
而SLAB分配器在linux系统中三种具体的实现:SLAB,SLUB,SLOB。目前内核代码中默认的SLAB分配器为SLUB算法。至于为啥不用SLAB大家可以网上看看资料,所以我们重点分析SLUB分配器的实现。
SLUB的原理是:
- SLUB的内存是从Buddy拿来的,是按照页的单位从Buddy拿过来。
- SLUB分配器会对从Buddy拿来的内存做二次分配,分配成每个小块,叫做object
- 每个SLUB都有一个名字,比如Kmalloc-128,当我们通过Kmalloc申请内存100字节的时候,就会去Kmalloc-128的slab里面去申请
- 当我们内存使用完毕后,需要将申请的100字节内存还给Kmalloc-128的slab的。
- 所以当我们再次申请同样的大小内存的时候就去对应的SLAB缓冲池去申请就行,可以提供效率。
cat /proc/slabinfo节点就可以看见系统中存在的slab信息
kmalloc-8192 274 304 8192 4 8 : tunables 0 0 0 : slabdata 76 76 0
kmalloc-4096 546 568 4096 8 8 : tunables 0 0 0 : slabdata 71 71 0
kmalloc-2048 1292 1360 2048 16 8 : tunables 0 0 0 : slabdata 85 85 0
kmalloc-1024 2134 2336 1024 32 8 : tunables 0 0 0 : slabdata 73 73 0
kmalloc-512 3648 3648 512 32 4 : tunables 0 0 0 : slabdata 114 114 0
kmalloc-256 2000 2784 256 32 2 : tunables 0 0 0 : slabdata 87 87 0
kmalloc-192 4894 5124 192 21 1 : tunables 0 0 0 : slabdata 244 244 0
kmalloc-128 3360 3360 128 32 1 : tunables 0 0 0 : slabdata 105 105 0
kmalloc-96 24906 24906 96 42 1 : tunables 0 0 0 : slabdata 593 593 0
kmalloc-64 84800 84800 64 64 1 : tunables 0 0 0 : slabdata 1325 1325 0
kmalloc-32 19456 19456 32 128 1 : tunables 0 0 0 : slabdata 152 152 0
kmalloc-16 12544 12544 16 256 1 : tunables 0 0 0 : slabdata 49 49 0
kmalloc-8 11264 11264 8 512 1 : tunables 0 0 0 : slabdata 22 22 0
kmem_cache_node 576 576 64 64 1 : tunables 0 0 0 : slabdata 9 9 0
kmem_cache 294 294 384 21 2 : tunables 0 0 0 : slabdata 14 14 0
我们通过自己创建一个新的slab,带大家走进SLUB。
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mm.h>
static struct kmem_cache* slub_test;
struct student
int age;
int score;
;
int slub_test_create_kmem(void)
int ret = -1;
slub_test = kmem_cache_create("slub_test", sizeof(struct student), 0, 0, NULL);
if(slub_test != NULL)
printk("slub_test create success!\\n");
ret=0;
return ret;
static int __init slub_test_init(void)
int ret;
printk("slub_test kernel module init\\n");
ret = slub_test_create_kmem();
return 0;
static void __exit slub_test_exit(void)
printk("slub_test kernel module exit\\n");
kmem_cache_destroy(slub_test);
module_init(slub_test_init);
module_exit(slub_test_exit);
此例子申请了一个名为slub_test的slub,我们编译为模块了。当我们插入此模块的时候,就会在/proc/slabinfo下生成一个slub_test的名字的slab
/ # cat /proc/slabinfo | grep "slub_test"
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
slub_test 0 0 8 512 1 : tunables 0 0 0 : slabdata 0 0 0
这个是插入模块后,出来的结果。而上面这些都是什么意思呢?接着分析各个字段啥意思,我们不按照顺序解释
- name: slub_test代表我们这个slab的名字叫slub_test
- pagesperslab: 意思是每一个slab需要几个page,可以看到名为slub_test的slab需要一个page,也就是4K。其实就是从buddy拿了一个order为0的一个页
- objsize: 代表的是每一个object的大小,我们传入的结构体sizeof(struct student)的大小就为8
- objperslab: 代表的一个就是一个slab中有多少个object,通过计算是512个。
注意:如果机器开启的SLUB_DEBUG选项,有可能都不是整除的,因为一个object中存在了一些debug调试区域
接着我们从我们创建的slab中申请一个object,目前我们名字slub_test的slab中是没有Object的。当通过kmem_cache_alloc去申请一个object的时候,就会从buddy去那一页,然后计算好各个各个object之间的联系,取出一个object给我们使用。上面kmem_alloc_create只是创建了一个slab,里面还没有真正的分配object的。
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/gfp.h>
static struct kmem_cache* slub_test;
struct student
int age;
int score;
;
struct student* zhangsan;
int slub_test_create_kmem(void)
int ret = -1;
slub_test = kmem_cache_create("slub_test", sizeof(struct student), 0, 0, NULL);
if(slub_test != NULL)
printk("slub_test create success!\\n");
ret=0;
zhangsan = kmem_cache_alloc(slub_test, GFP_KERNEL);
if(zhangsan != NULL)
printk("alloc object success!\\n");
ret = 0;
return ret;
static int __init slub_test_init(void)
int ret;
printk("slub_test kernel module init\\n");
ret = slub_test_create_kmem();
return 0;
static void __exit slub_test_exit(void)
printk("slub_test kernel module exit\\n");
kmem_cache_free(slub_test,zhangsan);
kmem_cache_destroy(slub_test);
module_init(slub_test_init);
module_exit(slub_test_exit);
这时候再次看看/proc/slabinfo下的结果
/proc/slabinfo | grep "slub_test"
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
slub_test 512 512 8 512 1 : tunables 0 0 0 : slabdata 1 1 0
可以看到数值有所变化:
- num_objs: 就是代表objects的最大个数
- active_objs:从代码中得出结果,如下
for_each_kmem_cache_node(s, node, n)
nr_slabs += node_nr_slabs(n);
nr_objs += node_nr_objs(n);
nr_free += count_partial(n, count_free);
sinfo->active_objs = nr_objs - nr_free;
sinfo->num_objs = nr_objs;
sinfo->active_slabs = nr_slabs;
sinfo->num_slabs = nr_slabs;
sinfo->objects_per_slab = oo_objects(s->oo);
sinfo->cache_order = oo_order(s->oo);
active_objects等于nr_objs - nr_free,nr_free的值是通过count_free计算出来的。free代表的意思是总共的object减去使用的inuse的。但是slab刚创建的时候insue等于object的
#ifdef CONFIG_SLUB_DEBUG
static int count_free(struct page *page)
return page->objects - page->inuse;
static inline unsigned long node_nr_objs(struct kmem_cache_node *n)
return atomic_long_read(&n->total_objects);
#endif /* CONFIG_SLUB_DEBUG */
page->inuse = page->objects;
page->frozen = 1;
这里的意思大概是inuse代表已经用完的,那slab肯定会使用完的,所以一开始inuse就等于object的数量的。
原理就是上图的样子:slab从buddy拿到一个order为0的内存,也就是一页,然后把这一页称为名为slub_test的slab,然后把这一页分成很多小的object的。
当我们使用的时候就从slab中获取一个object使用,用完了在归还给slab管理即可。
以上是关于SLUB的引入及举例说明的主要内容,如果未能解决你的问题,请参考以下文章