Memcached Slabs

本文详细介绍了基于N次幂的slab内存分配机制,包括slab子系统的初始化过程、对象大小对应的slab类别确定方法、内存分配与释放的具体实现等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. slabs.h

/* slabs memory allocation */

  1. /** Init the subsystem. 1st argument is the limit on no. of bytes to allocate,  
  2.     0 if no limit. 2nd argument is the growth factor; each slab will use a chunk  
  3.     size equal to the previous slab's chunk size times this factor.  
  4.     3rd argument specifies if the slab allocator should allocate all memory  
  5.     up front (if true), or allocate memory in chunks as it is needed (if false)  
  6. */   
  7. void  slabs_init( const  size_t limit,  const   double  factor,  const   bool  prealloc);  
  8. /**  
  9.  * Given object size, return id to use when allocating/freeing memory for object  
  10.  * 0 means error: can't store such a large object  
  11.  */   
  12. unsigned int  slabs_clsid( const  size_t size);  
  13. /** Allocate object of given length. 0 on error */   /*@null@*/   
  14. void  *do_slabs_alloc( const  size_t size, unsigned  int  id);  
  15. /** Free previously allocated object */   
  16. void  do_slabs_free( void  *ptr, size_t size, unsigned  int  id);  

 

2. slabs.c

  1. /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */   
  2. /*  
  3.  * Slabs memory allocation, based on powers-of-N. Slabs are up to 1MB in size  
  4.  * and are divided into chunks. The chunk sizes start off at the size of the  
  5.  * "item" structure plus space for a small key and value. They increase by  
  6.  * a multiplier factor from there, up to half the maximum slab size. The last  
  7.  * slab size is always 1MB, since that's the maximum item size allowed by the  
  8.  * memcached protocol.  
  9.  *  
  10.  */   
  11.   
  12. #define POWER_SMALLEST 1  
  13. #define POWER_LARGEST  200   
  14. #define POWER_BLOCK 1048576   
  15. #define CHUNK_ALIGN_BYTES 8   
  16. #define DONT_PREALLOC_SLABS   
  17. /* powers-of-N allocation structures */   
  18. typedef struct  {  
  19.     unsigned int  size;       /* sizes of items */   
  20.     unsigned int  perslab;    /* how many items per slab */   
  21.     void  **slots;            /* list of item ptrs */   
  22.     unsigned int  sl_total;   /* size of previous array */   
  23.     unsigned int  sl_curr;    /* first free slot */   
  24.     void  *end_page_ptr;          /* pointer to next free item at end of page, or 0 */   
  25.     unsigned int  end_page_free;  /* number of items remaining at end of last alloced page */   
  26.     unsigned int  slabs;      /* how many slabs were allocated for this class */   
  27.     void  **slab_list;        /* array of slab pointers */   
  28.     unsigned int  list_size;  /* size of prev array */   
  29.     unsigned int  killing;   /* index+1 of dying slab, or zero if none */   
  30. } slabclass_t;  
  31. static  slabclass_t slabclass[POWER_LARGEST + 1];  
  32. static  size_t mem_limit = 0;  
  33. static  size_t mem_malloced = 0;  
  34. static   int  power_largest;  
  35. static   void  *mem_base = NULL;  
  36. static   void  *mem_current = NULL;  
  37. static  size_t mem_avail = 0;  
  38. /*  
  39.  * Forward Declarations  
  40.  */   
  41. static   int  do_slabs_newslab( const  unsigned  int  id);  
  42. static   void  *memory_allocate(size_t size);  
  43. #ifndef DONT_PREALLOC_SLABS   
  44. /* Preallocate as many slab pages as possible (called from slabs_init)  
  45.    on start-up, so users don't get confused out-of-memory errors when  
  46.    they do have free (in-slab) space, but no space to make new slabs.  
  47.    if maxslabs is 18 (POWER_LARGEST - POWER_SMALLEST + 1), then all  
  48.    slab types can be made.  if max memory is less than 18 MB, only the  
  49.    smaller ones will be made.  */   
  50. static   void  slabs_preallocate ( const  unsigned  int  maxslabs);  
  51. #endif   

 

  1. /*  
  2.  * Figures out which slab class (chunk size) is required to store an item of  
  3.  * a given size.  
  4.  *  
  5.  * Given object size, return id to use when allocating/freeing memory for object  
  6.  * 0 means error: can't store such a large object  
  7.  */   
  8. unsigned int  slabs_clsid( const  size_t size) {  
  9.     int  res = POWER_SMALLEST;  
  10.     if  (size == 0)  
  11.         return  0;  
  12.     while  (size > slabclass[res].size)  
  13.         if  (res++ == power_largest)      /* won't fit in the biggest slab */   
  14.             return  0;  
  15.     return  res;  
  16. }  

 

  1. /**  
  2.  * Determines the chunk sizes and initializes the slab class descriptors  
  3.  * accordingly.  
  4.  */   
  5. void  slabs_init( const  size_t limit,  const   double  factor,  const   bool  prealloc) {  
  6.     int  i = POWER_SMALLEST - 1;  
  7.     unsigned int  size =  sizeof (item) + settings.chunk_size;  
  8.     /* Factor of 2.0 means use the default memcached behavior */   
  9.     if  (factor == 2.0 && size < 128)  
  10.         size = 128;  
  11.     mem_limit = limit;  
  12.     if  (prealloc) {  
  13.         /* Allocate everything in a big chunk with malloc */   
  14.         mem_base = malloc(mem_limit);  
  15.         if  (mem_base != NULL) {  
  16.             mem_current = mem_base;  
  17.             mem_avail = mem_limit;  
  18.         } else  {  
  19.             fprintf(stderr, "Warning: Failed to allocate requested memory in"   
  20.                     " one large chunk./nWill allocate in smaller chunks/n" );  
  21.         }  
  22.     }  
  23.     memset(slabclass, 0, sizeof (slabclass));  
  24.     while  (++i < POWER_LARGEST && size <= POWER_BLOCK / 2) {  
  25.         /* Make sure items are always n-byte aligned */   
  26.         if  (size % CHUNK_ALIGN_BYTES)  
  27.             size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);  
  28.         slabclass[i].size = size;  
  29.         slabclass[i].perslab = POWER_BLOCK / slabclass[i].size;  
  30.         size *= factor;  
  31.         if  (settings.verbose > 1) {  
  32.             fprintf(stderr, "slab class %3d: chunk size %6u perslab %5u/n" ,  
  33.                     i, slabclass[i].size, slabclass[i].perslab);  
  34.         }  
  35.     }  
  36.     power_largest = i;  
  37.     slabclass[power_largest].size = POWER_BLOCK;  
  38.     slabclass[power_largest].perslab = 1;  
  39.     /* for the test suite:  faking of how much we've already malloc'd */   
  40.     {  
  41.         char  *t_initial_malloc = getenv( "T_MEMD_INITIAL_MALLOC" );  
  42.         if  (t_initial_malloc) {  
  43.             mem_malloced = (size_t)atol(t_initial_malloc);  
  44.         }  
  45.     }  
  46. #ifndef DONT_PREALLOC_SLABS   
  47.     {  
  48.         char  *pre_alloc = getenv( "T_MEMD_SLABS_ALLOC" );  
  49.         if  (pre_alloc == NULL || atoi(pre_alloc) != 0) {  
  50.             slabs_preallocate(power_largest);  
  51.         }  
  52.     }  
  53. #endif   
  54. }  

 

  1. #ifndef DONT_PREALLOC_SLABS   
  2. static   void  slabs_preallocate ( const  unsigned  int  maxslabs) {  
  3.     int  i;  
  4.     unsigned int  prealloc = 0;  
  5.     /* pre-allocate a 1MB slab in every size class so people don't get  
  6.        confused by non-intuitive "SERVER_ERROR out of memory"  
  7.        messages.  this is the most common question on the mailing  
  8.        list.  if you really don't want this, you can rebuild without  
  9.        these three lines.  */   
  10.     for  (i = POWER_SMALLEST; i <= POWER_LARGEST; i++) {  
  11.         if  (++prealloc > maxslabs)  
  12.             return ;  
  13.         do_slabs_newslab(i);  
  14.     }  
  15. }  
  16. #endif   

 

  1. static   int  grow_slab_list ( const  unsigned  int  id) {  
  2.     slabclass_t *p = &slabclass[id];  
  3.     if  (p->slabs == p->list_size) {  
  4.         size_t new_size =  (p->list_size != 0) ? p->list_size * 2 : 16;  
  5.         void  *new_list = realloc(p->slab_list, new_size *  sizeof ( void  *));  
  6.         if  (new_list == 0)  return  0;  
  7.         p->list_size = new_size;  
  8.         p->slab_list = new_list;  
  9.     }  
  10.     return  1;  
  11. }  


  1. static   int  do_slabs_newslab( const  unsigned  int  id) {  
  2.     slabclass_t *p = &slabclass[id];  
  3. #ifdef ALLOW_SLABS_REASSIGN   
  4.     int  len = POWER_BLOCK;  
  5. #else   
  6.     int  len = p->size * p->perslab;  
  7. #endif   
  8.     char  *ptr;  
  9.     if  (mem_limit && mem_malloced + len > mem_limit && p->slabs > 0)  
  10.         return  0;  
  11.     if  (grow_slab_list(id) == 0)  return  0;  
  12.     ptr = memory_allocate((size_t)len);  
  13.     if  (ptr == 0)  return  0;  
  14.     memset(ptr, 0, (size_t)len);  
  15.     p->end_page_ptr = ptr;  
  16.     p->end_page_free = p->perslab;  
  17.     p->slab_list[p->slabs++] = ptr;  
  18.     mem_malloced += len;  
  19.     return  1;  
  20. }  

 

  1. /*@null@*/   
  2. void  *do_slabs_alloc( const  size_t size, unsigned  int  id) {  
  3.     slabclass_t *p;  
  4.     if  (id < POWER_SMALLEST || id > power_largest)  
  5.         return  NULL;  
  6.     p = &slabclass[id];  
  7.     assert(p->sl_curr == 0 || ((item *)p->slots[p->sl_curr - 1])->slabs_clsid == 0);  
  8. #ifdef USE_SYSTEM_MALLOC   
  9.     if  (mem_limit && mem_malloced + size > mem_limit)  
  10.         return  0;  
  11.     mem_malloced += size;  
  12.     return  malloc(size);  
  13. #endif   
  14.     /* fail unless we have space at the end of a recently allocated page,  
  15.        we have something on our freelist, or we could allocate a new page */   
  16.     if  (! (p->end_page_ptr != 0 || p->sl_curr != 0 || do_slabs_newslab(id) != 0))  
  17.         return  0;  
  18.     /* return off our freelist, if we have one */   
  19.     if  (p->sl_curr != 0)  
  20.         return  p->slots[--p->sl_curr];  
  21.     /* if we recently allocated a whole page, return from that */   
  22.     if  (p->end_page_ptr) {  
  23.         void  *ptr = p->end_page_ptr;  
  24.         if  (--p->end_page_free != 0) {  
  25.             p->end_page_ptr += p->size;  
  26.         } else  {  
  27.             p->end_page_ptr = 0;  
  28.         }  
  29.         return  ptr;  
  30.     }  
  31.     return  NULL;   /* shouldn't ever get here */   
  32. }  

 

  1. void  do_slabs_free( void  *ptr,  const  size_t size, unsigned  int  id) {  
  2.     slabclass_t *p;  
  3.     assert(((item *)ptr)->slabs_clsid == 0);  
  4.     assert(id >= POWER_SMALLEST && id <= power_largest);  
  5.     if  (id < POWER_SMALLEST || id > power_largest)  
  6.         return ;  
  7.     p = &slabclass[id];  
  8. #ifdef USE_SYSTEM_MALLOC   
  9.     mem_malloced -= size;  
  10.     free(ptr);  
  11.     return ;  
  12. #endif   
  13.     if  (p->sl_curr == p->sl_total) {  /* need more space on the free list */   
  14.         int  new_size = (p->sl_total != 0) ? p->sl_total * 2 : 16;   /* 16 is arbitrary */   
  15.         void  **new_slots = realloc(p->slots, new_size *  sizeof ( void  *));  
  16.         if  (new_slots == 0)  
  17.             return ;  
  18.         p->slots = new_slots;  
  19.         p->sl_total = new_size;  
  20.     }  
  21.     p->slots[p->sl_curr++] = ptr;  
  22.     return ;  
  23. }  

 

  1. static   void  *memory_allocate(size_t size) {  
  2.     void  *ret;  
  3.     if  (mem_base == NULL) {  
  4.         /* We are not using a preallocated large memory chunk */   
  5.         ret = malloc(size);  
  6.     } else  {  
  7.         ret = mem_current;  
  8.         if  (size > mem_avail) {  
  9.             return  NULL;  
  10.         }  
  11.         /* mem_current pointer _must_ be aligned!!! */   
  12.         if  (size % CHUNK_ALIGN_BYTES) {  
  13.             size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);  
  14.         }  
  15.         mem_current += size;  
  16.         if  (size < mem_avail) {  
  17.             mem_avail -= size;  
  18.         } else  {  
  19.             mem_avail = 0;  
  20.         }  
  21.     }  
  22.     return  ret;  

http://blog.developers.api.sina.com.cn/?p=124
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值