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的引入及举例说明的主要内容,如果未能解决你的问题,请参考以下文章

SLUB结构体创建及创建slab分析

SLUB结构体创建及创建slab分析

linux内核分析———SLAB原理及实现

原创Linux内存管理slub分配器

js中this的含义及用法?最好举例说明奥,不要纯理论的。。。

举例说明啥是组合关系,啥是聚合关系?