前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SLUB的引入及举例说明

SLUB的引入及举例说明

作者头像
DragonKingZhu
发布2020-04-30 18:18:29
1.4K0
发布2020-04-30 18:18:29
举报

我们都知道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信息

代码语言:javascript
复制
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。

代码语言:javascript
复制
#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

代码语言:javascript
复制
/ # 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的。

代码语言:javascript
复制
#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下的结果

代码语言:javascript
复制
/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:从代码中得出结果,如下
代码语言:javascript
复制
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的

代码语言:javascript
复制
#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管理即可。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-04-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档