stl内存池学习(二)——走近内存池

      这一节学习基础知识:所用到的数据结构。首先看内存池的接口:

Code:
  1. #ifndef _MEM_POOL_H   
  2. #define _MEM_POOL_H   
  3.   
  4. static size_t __freelist_index(size_t bytes);    
  5. static size_t __round_up(size_t bytes);   
  6.   
  7. static void *mem_malloc(size_t n);   
  8. static void mem_free(void *p, size_t n);   
  9. static void *mem_realloc(void* ptr, size_t new_sz, size_t old_sz)   
  10.   
  11. static void *refill(size_t n);   
  12. static char *chunk_alloc(size_t size, int *nobjs);   
  13.   
  14. #endif  

      用到的常量与变量:

Code:
  1. #define __MAX_BYTES 128     /* 小型区块的上限 */   
  2. #define __ALIGN 8           /* 小型区块的上调边界 */   
  3. #define __NFREELISTS __MAX_BYTES / __ALIGN /* 链表个数 */   
  4.   
  5. obj *free_list[__NFREELISTS]; /* 自由链表 */  
  6. static char *start_free;  /* 内存池起始位置 */  
  7. static char *end_free;    /* 内存池结束位置 */  
  8. static size_t heap_size;  /* 内存池大小 */  

      这里值得一提的是共用体obj,定义如下:

Code:
  1. typedef union obj {   
  2.     union obj *free_list_link;   
  3.     char client_data[1];   
  4. }obj;  

      一般情况下我们构建单链表时需要创建如下的一个结构体:
struct obj {
    obj *next; /* 指向下一个这样的结构体 */
    char *p;    /* 指向真正可用空间 */
    int size;    /* 记录空间的大小 */
};
      用户申请12字节的空间时使用时如下方式:
obj *pj = (obj *)malloc(12 +  sizeof(struct obj));
pj->next = NULL;
pj->p = (char*)p + sizeof(struct obj);
pj->size = 12;
      但是采用这种方式有个缺点就是我们需要花费额外的开销(记录指向下一个结点的指针和大小),我们可以通过直接定位链表在free_list数组中的位置来减掉 size 的开销,因为 free_list[0] 指向的是8 bytes的区块,free_list[1] 指向的是16 bytes的区块……。但仍需承担 next 和 p 指针的开销。
       当我们采用
union obj {
    union obj *free_list_link;
    char client_data[1];
};

    时,sizeof(obj)的大小为4,当然我们更不需负担这4个字节的开销。因为我们可以充分利用union的特性——同一时刻只存在一个变量。当我们构建空闲链表时,我们通过free_list_link指向下一个obj,当把这个obj分配出去的时候,我们直接返回client_data的地址。这样我们就不会在用户申请的空间上添加任何东西,达到了一物二用的结果。
      接下来看几个简单的函数:

Code:
  1. static size_t  __freelist_index(size_t bytes)   
  2. {   
  3.     return (bytes + __ALIGN - 1) / __ALIGN - 1;   
  4. }   
  5.   
  6. static size_t __round_up(size_t bytes)   
  7. {   
  8.     return (bytes + __ALIGN - 1) & ~(__ALIGN - 1);   
  9. }  


      __freelist_index的作用是函数根据区块的大小,决定使用第n号free-list。n从0算起。__round_up用于将bytes上调至 __ALIGN 的倍数。
      接下来要进入几个主要的函数学习了。

你可能感兴趣的:(stl内存池学习(二)——走近内存池)