STL内存管理的C实现

  1. //STL 内存管理器的C实现

  2. #include stdio.h>
  3. #include stdlib.h>

  4. #define __ALIGN 8    //小型区块上调边界
  5. #define __MAX_BYTES 128    //小型区块大小的上限
  6. #define __NFREELISTS (__ALIGN/__MAX_BYTES)    //free-lists的个数

  7. typedef union obj{
  8.     union obj *free_list_link;
  9.     char client_data[1];
  10. }obj;
  11. obj *free_list[__NFREELISTS];
  12. char *start_free;    //mempool开始位置
  13. char *end_free;    //mempool结束位置
  14. size_t heapsize;

  15. size_t ROUND_UP(size_t bytes);
  16. size_t FREELIST_INDEX(size_t bytes);
  17. void *stl_malloc(size_t nbytes);
  18. void stl_free(void *p, size_t nbytes);
  19. void *refill(size_t n);
  20. char *chunk_alloc(size_t bytes, size_t *nobjs);


  21. int main(){
  22.     int len= 65;
  23.     void *ptr = stl_malloc(len);
  24.     printf("%p\n", ptr);
  25.     stl_free(ptr, len);
  26.     return 0;
  27. }

  28. //将bytes上调到__ALIGN的倍数
  29. size_t ROUND_UP(size_t bytes){
  30.     return ((bytes + __ALIGN - 1) & ~(__ALIGN - 1));
  31. }
  32. //返回bytes所对应的freelist索引号
  33. size_t FREELIST_INDEX(size_t bytes){
  34.     return ((bytes + __ALIGN - 1) / __ALIGN - 1);
  35. }
  36. void *stl_malloc(size_t nbytes){
  37.     if(nbytes > 128){
  38.         return malloc(nbytes);
  39.     }
  40.     obj **my_free_list;
  41.     obj *result;
  42.     my_free_list = free_list + FREELIST_INDEX(nbytes);
  43.     result = *my_free_list;
  44.     if(result == NULL){
  45.         void *r = refill(ROUND_UP(nbytes));
  46.         return r;
  47.     }
  48.     //取出空闲块
  49.     *my_free_list = result->free_list_link;
  50.     return result;
  51. }
  52. void stl_free(void *p, size_t nbytes){
  53.     obj *q = (obj *)p;
  54.     obj **my_free_list;
  55.     if(nbytes > (size_t)__MAX_BYTES){
  56.         free(p);
  57.         return;
  58.     }
  59.     my_free_list = free_list + FREELIST_INDEX(nbytes);
  60.     q->free_list_link = *my_free_list;
  61.     *my_free_list = q;
  62. }
  63. void *refill(size_t n){
  64.     //默认从内存池取得20个块,多个块构成一个chunk
  65.     size_t nobjs = 20;    //-结果参数
  66.     char *chunk = chunk_alloc(n, &nobjs);    
  67.     if(!chunk){
  68.         return NULL;
  69.     }
  70.     obj **my_free_list;
  71.     obj *result, *cur_obj, *next_obj;
  72.     int i;
  73.     //内存池空间告急仅返回一个块,则直接返回给用户
  74.     if(nobjs == 1){
  75.         return chunk;
  76.     }
  77.     //否则准备向free_list中纳入新的节点
  78.     my_free_list = free_list + FREELIST_INDEX(n);
  79.     //以下在chunk的连续空间上建立free_list
  80.     result = (obj *)chunk;    //此块返回给用户
  81.     *my_free_list = next_obj = (obj *)(chunk + n);
  82.     for(i = 1; ; i++){
  83.         cur_obj = next_obj;
  84.         next_obj = (obj *)((char *)next_obj + n);
  85.         if(nobjs - 1 == i){
  86.             cur_obj->free_list_link = NULL;
  87.             break;
  88.         }else{
  89.             cur_obj->free_list_link = next_obj;    
  90.         }
  91.     }
  92.     return result;
  93. }
  94. //从内存池取连续的块空间
  95. char *chunk_alloc(size_t bytes, size_t *nobjs){
  96.     char *result;
  97.     size_t total_bytes = bytes * (*nobjs);    //要求的字节数
  98.     size_t bytes_left = end_free - start_free;    //

  99.     //内存池空间宽裕
  100.     if(bytes_left >= total_bytes){
  101.         result = start_free;
  102.         start_free += total_bytes;
  103.         return result;
  104.     }else if(bytes_left >= bytes){
  105.         //不够分配全部的,但是还可以分配一个或多个块
  106.         *nobjs = bytes_left/bytes;
  107.         total_bytes = *nobjs * bytes;
  108.         result = start_free;
  109.         start_free += total_bytes;
  110.         return result;
  111.     }else{
  112.         //内存池黔驴技穷了,连一个块的空间都没有了
  113.         size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heapsize >> 4);
  114.         if(bytes_left > 0){
  115.             //内存池中还有一些零头,先配给适当的free-list
  116.             obj **my_free_list = free_list + FREELIST_INDEX(bytes_left);
  117.             ((obj *)start_free)->free_list_link = *my_free_list;
  118.             *my_free_list = (obj *)start_free;
  119.         }
  120.         start_free = (char *)malloc(bytes_to_get);
  121.         if(start_free == NULL){
  122.             //看看更大块的free_list有无可用块
  123.             int i;
  124.             obj **my_free_list, *p;
  125.             for(i = bytes; i = __MAX_BYTES; i += __ALIGN){
  126.                 my_free_list = free_list + FREELIST_INDEX(i);
  127.                 p = *my_free_list;
  128.                 if(p){
  129.                     *my_free_list = p->free_list_link;
  130.                     start_free = (char *)p;
  131.                     end_free = start_free + i;
  132.                     //递归调用自己,按新的状态重新分配,并修正nobjs;
  133.                     return chunk_alloc(bytes, nobjs);
  134.                 }
  135.             }
  136.             //实在没有空间了
  137.             end_free = 0;
  138.             return NULL;
  139.         }
  140.         heapsize += bytes_to_get;
  141.         end_free = start_free + bytes_to_get;
  142.         return chunk_alloc(bytes, nobjs);
  143.     }
  144.     
  145. }
上一篇:Android之拖动条(SeekBar和RatingBar)的功能和用法


下一篇:Learning Disentangled Representations for Recommendation | NIPS 2019 论文解读