• [CNT]关于自己的一个小小的slab内存分配器


    引言:应用级别的内存分配器的作用主要在于减少malloc函数的调用,降低系统的内存碎片。作为高性能的服务器,一般都会有自己的内存分配方案。slab作为一款Linux内核的经典内存分配方式,应用在很多的应用级别的软件上,比如说Memcached 等。

            今天的主题就分享一下最近写的slab的一个简单的Demo,在于分享,代码有些粗糙,比如缺少对于内存字节的比例因子,缺少关于内存不足的情况下重分配等。不过各种应用各有各自的用途,在实现某些cached操作的软件中,由于带有LRU 算法等,在内存快使用完后就采取淘汰策略,所以不一定在内存不足的情况下重新给操作系统分配。

    Slab内存分配器原理:

            

    此图片来自自己的另一篇博文,如若不能显示,请google slab 内存分配器

    slab内存分配器的原理大致如图所示,由index 确定一个由slot 组成的链表,这里也可以设置为一个固定长度大小的结构,然后划分为不同大小的slot

    两种方式都有自己的好处,采用链表的方式可以动态增长,采用固定长度大小的块结构结构清晰,可以采用链式的数组构造slot,然后由empty_index 来确定空闲的slot,本篇博文就是讲解采用了这种方式的管理的。稍后会有详解,这里只是作为简单介绍。

    我们只需要了解可以通过对齐后的内存大小找到index,然后通过index 找到slot数组,通过empty_index找到空闲的slot,改变empty_index 使其指向下一个空闲的slot。

    对齐宏:

    #define ALIGN(a,size) ((a+size-1)&(~(size-1)))

    a为申请的内存大小,size为内存对齐大小

    比如说 a = 127 size = 128 , 那么小于128 的将a转化为128,总的来说,就是128的整数倍。

    很多人说这样的方式会导致内存浪费,但是至今几乎都是采用这种方式。在没有找到一个更好的方式以前,这个也许就是最好的方式吧。

    通过对齐后的内存大小,找到对应的index 是很容易的。比如说,我们的内存对齐是64,我们只需要将申请的 a>>6 .

    #define MC_SLOT_ALIGN_SIZE  (64)

    我们定义了默认的内存字节就是64Byte.可以通过自己的喜好做修改

    解释一下这里的命名方式,CHUNK_ARRAY 就是由index 作为下标的数组。

    我们定义

    #define MC_CHUNK_ARRAY_SIZE (16)

    就是说,index最大为15    0 不做为index。

    每一个slot 的结构是这样定义的:

    1 typedef struct _slot_s
    2 {
    3     struct _slot_s         *data               ; /* The next              empty slot */
    4     mc_address             *star               ;
    5     mc_address             *end                ;
    6     mc_length               slot_length        ;
    7     int                     slot_index         ;
    8     mc_chunk_t             *which_chunk_p      ;
    9 }mc_slot_t;

    data 指针作为连接slot 数组的每一个槽的指针存在着,另一种方式是设置为 void *data ,这样可以复用 data指针,在申请出来后可以作为指向数据的指针。

    1 #define mc_address        unsigned char 
    2 
    3 #define mc_length         unsigned int  

    mc_address  *start 用于指向slot申请的真正的内存地址,一般由malloc来申请。

    mc_address  *end 指向内存的末尾。 end - start == slot_length 

    slot_index 用于表示此slot是位于slot数组的下标

    mc_chunkt_t   *which_chunk_p 是用来表示属于哪一个chunk 的,这个指针可以在释放的时候降低接口复杂度。

    下面看看chunk的结构表示:

    1 struct _chunk_s
    2 {
    3     mc_length       chunk_length              ;
    4     mc_slot_t       *slots                    ;
    5     int             slots_size                ;  /*(int)(MC_CHUNK_SIZE/ALIGN(i,MC_SLOT_ALIGN_SIZE))*/
    6     int             empty_slot_index          ;
    7     int             last_slot_num             ;
    8     int             slots_array_num           ;  /*slot array size */
    9 };

    chunk_length 为宏定义的MC_CHUNK_ARRAY_SIZE 

    slots 是一个指针,指向不同的slot数组,这里的slot数组也是通过动态分配的。后面会贴出相应代码。

    slots_size是这个chunk下的slot数组中slot的内存大小。即end-statr

    empty_slot_index是空闲的slot的index,这中数据结构可以查看类似的nginx的connection数组。

    last_slot_num作为标示剩余的slot数量

    slots_array_num是slot的数组的大小

    下面看看头文件中的函数声明:

     1 mc_slab_t * mc_slab_create(void);
     2     /*
     3      *    This function create a handle of slab and 
     4      *  you can use this handle to alloc slot
     5      *  besieds,when you free the slab , you must take this
     6      *  handle as a argument of mc_slab_free function
     7      */
     8      
     9 mc_slot_t * mc_slot_alloc( mc_slab_t * par_slab , size_t par_size );
    10     /*
    11      *    mc_slot_alloc first arg is handle created by mc_slab_create
    12      *    the second arg is memory size you want
    13      *    NOTICE:because of handle is a global value , so this function is 
    14      *    not thread safty
    15      */
    16 
    17 int mc_slot_free( mc_slot_t * par_slot_p );
    18     /*
    19      *    mc_slot_free take a slot structure as argument
    20      *    return 1 indicate successed
    21      *    
    22      *    this function find the lowest index of slot array     
    23      *  It's simple but useful
    24      */
    25 
    26 void mc_slab_free( mc_slab_t * par_slab );
    27     /*
    28      *    free the whole slab
    29      *    argument is handle of create by mc_slab_create
    30      *    
    31      *    well done ,this function is test by valgrind and not memory leak

    大致就是这几个函数,功能有说明。

      1
      3 
      4 mc_slab_t * mc_slab_create(void)
      5 {
      6     mc_chunk_t *p_chunk ;
      7     mc_slot_t  *p_slot  ;
      8     int i;
      9     int j;
     10     
     11     int chunk_array_size = MC_CHUNK_ARRAY_SIZE  ;
     12     /* MALLOC */
     13     mc_slab_t * ret_big_array_p = (mc_slab_t *)malloc( sizeof(mc_slab_t) );
     14     
     15     /* alloc memory for chunk_array */
     16     /* MALLOC */
     17     ret_big_array_p->chunk_array = (mc_chunk_t *)malloc( sizeof(mc_chunk_t)*MC_CHUNK_ARRAY_SIZE );
     18     
     19     ret_big_array_p->total_alloced = MC_CHUNK_SIZE * MC_CHUNK_ARRAY_SIZE ;
     20     
     21     ret_big_array_p->chunk_array_size = MC_CHUNK_ARRAY_SIZE ;
     22     
     23     p_chunk =     ret_big_array_p->chunk_array ;
     24     
     25     /*
     26     p_chunk[0] = NULL ;
     27     */
     28     for( i = 1 ; i < chunk_array_size ; i++ )
     29     {
     30         p_chunk[i].chunk_length = MC_CHUNK_SIZE ;
     31         
     32         /* every slot has a stable size of MC_CHUNK_SIZE */
     33         p_chunk[i].slots_size = (int)(MC_CHUNK_SIZE/ALIGN(i,MC_SLOT_ALIGN_SIZE));
     34         
     35         /* alloc memory for slots every chunk */
     36         /* MALLOC */
     37         p_chunk[i].slots = (mc_slot_t *)malloc( sizeof(mc_slot_t)*p_chunk[i].slots_size );
     38         
     39         p_chunk[i].empty_slot_index = 0 ;
     40         
     41         p_chunk[i].last_slot_num = p_chunk[i].slots_size ;
     42         
     43         p_chunk[i].slots_array_num = p_chunk[i].slots_size ;
     44         
     45         
     46         
     47         /*initialize the slots*/
     48         j = p_chunk[i].slots_size - 1 ; 
     49         /*slot_size = */
     50         
     51         int slot_alloc_size = i<<6 ;
     52         
     53         /* ini the last slot of slot array */
     54         p_chunk[i].slots[j].data = NULL ;
     55         
     56         /* MALLOC */
     57         p_chunk[i].slots[j].star = (void *)malloc( slot_alloc_size );
     58         ret_big_array_p->total_lasted += slot_alloc_size ;
     59         p_chunk[i].slots[j].end = p_chunk[i].slots[j].star + slot_alloc_size ;
     60         p_chunk[i].slots[j].slot_length = slot_alloc_size ;
     61         p_chunk[i].slots[j].slot_index  = j ;
     62         p_chunk[i].slots[j].which_chunk_p = &(p_chunk[i]);
     63         
     64         /* for other slots initialize */
     65         for( j = p_chunk[i].slots_size -2 ; j >= 0 ; j-- )
     66         {
     67             p_chunk[i].slots[j].data = &(p_chunk[i].slots[j+1]) ;
     68             
     69             /* MALLOC */
     70             p_chunk[i].slots[j].star = (void *)malloc( slot_alloc_size );
     71             ret_big_array_p->total_lasted += slot_alloc_size ;
     72             
     73             p_chunk[i].slots[j].end = p_chunk[i].slots[j].star + slot_alloc_size ;
     74             
     75             p_chunk[i].slots[j].slot_length = slot_alloc_size ;
     76             
     77             p_chunk[i].slots[j].slot_index  = j ;
     78             
     79             p_chunk[i].slots[j].which_chunk_p = &(p_chunk[i]);
     80         }
     81     }
     82     ret_big_array_p->total_alloced    = 0 ;
     83     
     84     
     85     /* flag of wether this block is initialized  */
     86     ret_big_array_p->is_initialized = 1 ;
     87     return ret_big_array_p ;
     88 }
     89 
     90 mc_slot_t * mc_slot_alloc( mc_slab_t * par_slab , size_t par_size )
     91 {
     92     if( par_slab == NULL || par_slab->is_initialized != 1 )
     93     {
     94         /*There may be some debug information*/
     95         return NULL ;
     96     }
     97     
     98     /* args checked right */
     99     
    100     mc_slot_t * ret_slot_p ;
    101     size_t  allocsize = ALIGN( par_size,MC_SLOT_ALIGN_SIZE ) ;
    102     int     chunk_index = allocsize >> 6 ;
    103     
    104     if( chunk_index >= MC_CHUNK_ARRAY_SIZE )
    105     {
    106         /* to protected out of chunk[] bound */
    107         /*We should do someting At least we should let users know there was no slot for him */
    108         return NULL ;
    109         
    110     } 
    111     
    112     if( par_slab->chunk_array[ chunk_index ].last_slot_num == 0 )
    113     {
    114         /*we should do something eh ??*/
    115         /*At least we should let user know there was no slot for him */
    116         return NULL ;
    117     }
    118     
    119     mc_chunk_t * p_chunk = &(par_slab->chunk_array[ chunk_index ]);
    120     int        empty_index = p_chunk->empty_slot_index ;
    121     
    122     /* find a empty slot for ret_slot_p point */
    123     ret_slot_p = &(p_chunk->slots[empty_index]) ;
    124     
    125     /* we should change the chunk's empty index */
    126     
    127     p_chunk->empty_slot_index = ret_slot_p->data->slot_index ;
    128     
    129     (p_chunk->last_slot_num)-- ;
    130     return ret_slot_p ;
    131     
    132 }
    133 
    134 
    135 
    136 /* Notice ! free slot but not slab  */
    137 int mc_slot_free( mc_slot_t * par_slot_p )
    138 {
    139     mc_chunk_t * chunk_p = par_slot_p->which_chunk_p ;
    140     chunk_p->slots[chunk_p->empty_slot_index].data = par_slot_p ; 
    141     chunk_p->empty_slot_index = par_slot_p->slot_index;
    142     (chunk_p->last_slot_num)++ ;
    143     return 1 ;
    144 }
    145 
    146 void mc_slab_free( mc_slab_t * par_slab )
    147 {
    148     mc_chunk_t * chunk_p       ;
    149     mc_chunk_t * free_chunk_p ;
    150     mc_slot_t  * slot_p        ;
    151     mc_slot_t  * free_slot_p  ;
    152     
    153     
    154     /* free each slot first */
    155     int i = 0 ; 
    156     int j = 0 ;
    157     
    158     for( i = 1 ; i < MC_CHUNK_ARRAY_SIZE ; i++ )
    159     {
    160         
    161         chunk_p = &(par_slab->chunk_array[i]);
    162     
    163         slot_p = chunk_p->slots;
    164         
    165         for( j = 0 ; j < chunk_p->slots_array_num ; j++ )
    166         {
    167             free(slot_p[j].star);
    168         }
    169         free( slot_p );        
    170     }
    171     free( par_slab->chunk_array );
    172     free( par_slab );
    173 }
    174 
    175 
    176 /*
    177 int main()
    178 {
    179     mc_slab_t *my_slab = mc_slab_create();
    180     fprintf(stderr,"%d\n",my_slab->total_lasted);
    181     mc_slot_t * my_slot = mc_slot_alloc( my_slab, 127 ) ;
    182     fprintf(stderr,"%p\n",my_slot->star);
    183     fprintf(stderr,"%p\n",my_slot->end);
    184     fprintf(stderr,"%d\n",my_slot->slot_index);
    185     fprintf(stderr,"%d\n",my_slot->slot_length);
    186     
    187     my_slot = mc_slot_alloc( my_slab, 127 ) ;
    188     fprintf(stderr,"%p\n",my_slot->star);
    189     fprintf(stderr,"%p\n",my_slot->end);
    190     fprintf(stderr,"%d\n",my_slot->slot_index);
    191     fprintf(stderr,"%d\n",my_slot->slot_length);
    192     
    193     my_slot = mc_slot_alloc( my_slab, 127 ) ;
    194     fprintf(stderr,"%p\n",my_slot->star);
    195     fprintf(stderr,"%p\n",my_slot->end);
    196     fprintf(stderr,"%d\n",my_slot->slot_index);
    197     fprintf(stderr,"%d\n",my_slot->slot_length);
    198     
    199     my_slot = mc_slot_alloc( my_slab, 127 ) ;
    200     fprintf(stderr,"%p\n",my_slot->star);
    201     fprintf(stderr,"%p\n",my_slot->end);
    202     fprintf(stderr,"%d\n",my_slot->slot_index);
    203     fprintf(stderr,"%d\n",my_slot->slot_length);
    204     
    205     mc_slot_free(my_slot);
    206     my_slot = mc_slot_alloc( my_slab, 127 ) ;
    207     fprintf(stderr,"%p\n",my_slot->star);
    208     fprintf(stderr,"%p\n",my_slot->end);
    209     fprintf(stderr,"%d\n",my_slot->slot_index);
    210     fprintf(stderr,"%d\n",my_slot->slot_length);
    211     
    212     my_slot = mc_slot_alloc( my_slab, 127 ) ;
    213     fprintf(stderr,"%p\n",my_slot->star);
    214     fprintf(stderr,"%p\n",my_slot->end);
    215     fprintf(stderr,"%d\n",my_slot->slot_index);
    216     fprintf(stderr,"%d\n",my_slot->slot_length);
    217     
    218     my_slot = mc_slot_alloc( my_slab, 62 ) ;
    219     fprintf(stderr,"%p\n",my_slot->star);
    220     fprintf(stderr,"%p\n",my_slot->end);
    221     fprintf(stderr,"%d\n",my_slot->slot_index);
    222     fprintf(stderr,"%d\n",my_slot->slot_length);
    223     
    224     mc_slab_free(my_slab);
    225     
    226     return 0;
    227 }
    228     
    229 */
        

    总结:slab内存分配器的核心在于理解通过对齐后的内存大小得到index

    文章属原创,转载请注明出处 联系作者: Email:zhangbolinux@sina.com QQ:513364476
  • 相关阅读:
    BZOJ.2199.[USACO2011 Jan]奶牛议会(2-SAT)
    BZOJ.1997.[HNOI2010]Planar(2-SAT)
    POJ.3648.Wedding(2-SAT)
    POJ.3678.Katu Puzzle(2-SAT)
    POJ.3207.Ikki's Story IV-Panda's Trick(2-SAT)
    洛谷.4180.[模板]次小生成树Tree(Kruskal LCA 倍增)
    BZOJ.4766.文艺计算姬(Prufer)
    zabbix 微信告警机制
    网络地址
    tcp与udp的区别
  • 原文地址:https://www.cnblogs.com/Bozh/p/slab.html
Copyright © 2020-2023  润新知