一个简单的固定长度内存池的实现



当频繁地用malloc申请内存,然后再用free释放内存时,会存在两个主要问题。第一个问题是频繁的分配释放内存可能导致系统内存碎片过多;第二个问题是分配释放内存花费的时间可能比较多(这个问题不太明显)。这个时候我们就可以考虑使用内存池了。

最朴素的内存池思想就是,首先你向系统申请一块很大的内存(这块内存因为很大,以致于我们常称它为memory pool),然后你在上面实现类似于malloc和free等操作。当你需要分配内存时,你用自己的类malloc函数从内存池上取一小块给使用者(后文称之为小内存块),当用类free函数释放从内存池上取得的内存时,这个小内存块也并不归还给系统,而只是还给内存池。

最近写telnet还原程序,写了个简易内存池,和大家分享下。

这个内存池提供这样的功能:i)提供类malloc函数mem_alloc从内存池上获取固定大小的内存,提供类free函数mem_free释放内存到内存池中;ii)内存池初始大小为某个固定大小(BUF_SIZE)的n倍,当内存池中的内存不够用时,内存池能以一定步长增长直到无系统内存。

要实现这些功能,首先应该用一个数据结构(mem_node_t)将内存池中的各个小内存块挂起来;然后为了使内存池能够以一定步长增长,我们要能分配多个大的内存块(即多个小内存池),为了能顺利的管理各个大的内存块,需要一个数据结构(mem_block_t)来记录这些信息;最后,内存池的当前状态(包括可分配的空闲链表,空闲的小内存块的个数等)是我们感兴趣的东西,所以用数据结构(mem_pool_t)来记录。

      
      
  1. typedef union _mem_node 
  2.        union _mem_node *next; 
  3.        char buf[BUF_SIZE]; 
  4. }mem_node_t, *pmem_node_t; 
  5. typedef struct _mem_block 
  6.        mem_node_t *node_head; /* 第一个小内存块 */ 
  7.        mem_node_t *node_tail;  /* 最后一个小内存块 */ 
  8.        int node_cnt; /* node count */ 
  9.        struct _mem_block *next 
  10. }mem_block_t, *pmem_block_t; 
  11. typedef struct _mem_pool 
  12.        mem_block_t *block_head; /* 第一个大内存块 */ 
  13.        mem_block_t *block_tail; /* 最后一个大内存块 */ 
  14.        mem_node_t *free_head; /* 当前空闲链表的头指针 */ 
  15.        int block_cnt; /* block count */ 
  16.        int free_cnt; /* free node count; */ 
  17.        int base; /* 内存池的初始大小 */ 
  18.        int step; /* 内存池的增长步长 */ 
  19. }mem_pool_t, *pmem_pool_t; 

然后提供了一些操作函数:mem_pool_init用来初始化内存池;mem_pool_destroy用来释放内存池,将内存池所占空间归还系统;print_mem_pool_info用来打印内存池的信息;mem_alloc,用来从内存池上分配小内存块;mem_free,将小内存块归还给内存池。

mem_alloc和mem_free操作的就是内存池的空闲链表,前者从空闲链表取一个结点,后者将一个结点插入空闲链表。而这个空闲链表是由mem_pool_init初始化的,而且当内存池增长时,即增加新的大内存块时,我们将大内存块上的小内存块也挂接到这个空闲链表上来。需要注意的是小内存块的数据结构用了联合,这是因为小内存块要么是挂接在空闲链表上,要么是分配给了用户,必居且只能居这两种状态之一,这个数据结构可根据需求适当改进。

在码代码之前,要补充说明的是,不少内存池都提供了分配不同大小的内存块的功能,将多个不同大小的本内存池链接起来也可实现这些功能,改动是比较容易的^_^

最后,本内存池在vc6下验证当频繁分配释放100字节大小的内存时,本内存池效率约是直接malloc和free的10倍,当分配大小变小时,效率比有所降低,但当分配大小增大时,效率比有所升高,分配1000字节大小的内存时,效率比约为100。

代码:

      
      
  1. /************************mem_pool.h************************ 
  2. *author:bripengandre 
  3. * 
  4. **********************************************************/ 
  5. #ifndef _MEM_POOL_H_ 
  6. #define _MEM_POOL_H_ 
  7.   
  8. #define BUF_SIZE  100 
  9. #define BASE_COUNT 10000 
  10. #define STEP_COUNT 1000 
  11. /* #pragma pack () */ 
  12. /*  */ 
  13. typedef union _mem_node 
  14.     union _mem_node *next; 
  15.     char buf[BUF_SIZE]; 
  16. }mem_node_t, *pmem_node_t; 
  17.   
  18. /* used to store block information */ 
  19. typedef struct _mem_block 
  20.     mem_node_t *node_head; 
  21.     mem_node_t *node_tail; 
  22.     int node_cnt; /* node count */ 
  23.     struct _mem_block *next; 
  24. }mem_block_t, *pmem_block_t; 
  25.   
  26. /* used to store the pool information */ 
  27. typedef struct _mem_pool 
  28.     mem_block_t *block_head; 
  29.     mem_block_t *block_tail; 
  30.     mem_node_t *free_head; 
  31.     int block_cnt; /* block count */ 
  32.     int free_cnt; /* free node count; */ 
  33.     int base; 
  34.     int step; 
  35. }mem_pool_t, *pmem_pool_t; 
  36.   
  37. /*  mem_pool will have at least base blocks, and will increase
  38.  steps a time if needed */ 
  39. int mem_pool_init(int base, int step); 
  40. void mem_pool_destroy(void); 
  41. void print_mem_pool_info(void); 
  42. /* since the block size is constant, this function need no input parameter */ 
  43. void *mem_alloc(void); 
  44. void mem_free(void *ptr); 
  45.   
  46. #endif /* _MEM_POOL_H */ 
  47. /************************mem_pool.c************************ 
  48. *author:bripengandre 
  49. **********************************************************/ 
  50. #include "mem_pool.h" 
  51. #include <stdio.h> 
  52. #include <string.h> 
  53. #include <stdlib.h> 
  54.   
  55. #define MEM_POOL_DEBUG 
  56.  
  57. /* add new memory block to our memory pool */ 
  58. static int add_mem_block(int cnt); 
  59. /* init the new block */ 
  60. static int mem_block_init(int cnt, mem_block_t *block); 
  61. /* init free_list of the new block */ 
  62. static int free_list_init(const mem_block_t *block); 
  63.   
  64. static mem_pool_t mem_pool; 
  65. /*  mem_pool will have at least base blocks, 
  66. and will increase steps a time if needed */ 
  67. int mem_pool_init(int base, int step) 
  68. {       
  69.    if(base <= 0) 
  70.    { 
  71.     base = BASE_COUNT; 
  72.     } 
  73.     if(step <= 0) 
  74.     { 
  75.     step = STEP_COUNT; 
  76.     } 
  77.     /* initiate mem_pool */ 
  78.     memset(&mem_pool, 0, sizeof(mem_pool)); 
  79.     mem_pool.base = base; 
  80.     mem_pool.step = step; 
  81.     /* add the base block(node of base count) into the memory pool */ 
  82.     if(!add_mem_block(base)) 
  83.     { 
  84.     fprintf(stderr, "mem_pool_init::add_mem_block error/n"); 
  85.     return 0; 
  86.     } 
  87.     return 1; 
  88.  
  89. void mem_pool_destroy(void
  90.     mem_block_t *prev, *cur; 
  91.     prev = NULL; 
  92.     cur = mem_pool.block_head; 
  93.     while(prev != NULL) 
  94.     { 
  95.     prev = cur; 
  96.     cur = cur->next; 
  97.     free(cur->node_head); 
  98.     free(prev); 
  99.     } 
  100.          
  101.     memset(&mem_pool, 0, sizeof(mem_pool_t)); 
  102.  
  103. void print_mem_pool_info(void
  104.    int i; 
  105.    mem_block_t *p; 
  106.    if(mem_pool.block_head == NULL) 
  107.    { 
  108.       fprintf(stderr, "memory pool has been created!/n"); 
  109.       return
  110.    } 
  111.    printf("***************memory pool information start***********************/n"); 
  112.         printf("block count: %4d/n", mem_pool.block_cnt); 
  113.         printf("current free node count: %4d/n", mem_pool.free_cnt); 
  114.     printf("base block size: %4d/n", mem_pool.base); 
  115.     printf("increasing block size: %4d/n", mem_pool.step); 
  116.     printf("the first block: %#x/n", mem_pool.block_head); 
  117.     printf("the last block: %#x/n", mem_pool.block_tail); 
  118.     printf("the first free node: %#x/n/n", mem_pool.free_head); 
  119.     for(p = mem_pool.block_head, i = 0; p != NULL; p = p->next, i++) 
  120.     { 
  121.     printf("-------------------block %4d--------------------------/n", i+1); 
  122.     printf("node count: %4d/n", p->node_cnt); 
  123.     printf("the first node: %#x/n", p->node_head); 
  124.     printf("the last node: %#x/n", p->node_tail); 
  125.     printf("------------------------------------------------------/n"); 
  126.     } 
  127.     printf("*****memory pool information end****/n"); 
  128.  
  129. /* since the block size is constant, this function need no input parameter */ 
  130. void *mem_alloc(void
  131.     mem_node_t *p; 
  132.     /* no free node ready, attempt to allocate new free node */ 
  133.     if(mem_pool.free_head == NULL) 
  134.     { 
  135.     if(!add_mem_block(mem_pool.step)) 
  136.     { 
  137.         return NULL; 
  138.     } 
  139.     } 
  140.          
  141.     /* get free node from free_list */ 
  142.     p = mem_pool.free_head; 
  143.     mem_pool.free_head = p->next; 
  144.     /* decrease the free node count */ 
  145.     mem_pool.free_cnt--; 
  146.     return p; 
  147.  
  148. void mem_free(void *ptr) 
  149.     if(ptr == NULL) 
  150.     { 
  151.     return
  152.     }       
  153.     /* return the node to free_list */ 
  154.     ((mem_node_t *)ptr)->next = mem_pool.free_head; 
  155.     mem_pool.free_head = ptr; 
  156.     /* increase the free node count */ 
  157.     mem_pool.free_cnt++; 
  158.  
  159. /* add new memory block to our memory pool */ 
  160. static int add_mem_block(int cnt) 
  161.     mem_block_t *block; 
  162.     if( (block = malloc(sizeof(mem_block_t))) == NULL) 
  163.     { 
  164.        fprintf(stderr, "add_mem_block::malloc error/n"); 
  165.      return 0; 
  166.     }            
  167.     memset(block, 0, sizeof(mem_block_t)); 
  168.     if(!mem_block_init(cnt, block)) 
  169.     { 
  170.     fprintf(stderr, "mem_pool_init::mem_block_init error/n"); 
  171.     return 0; 
  172.     } 
  173.     /* insert the new block in the head */ 
  174.     block->next = mem_pool.block_head; 
  175.     mem_pool.block_head = block; 
  176.     if(mem_pool.block_tail == NULL) 
  177.     { 
  178.     mem_pool.block_tail = block; 
  179.     } 
  180.     
  181.     /* insert the new block into the free list */ 
  182.     block->node_tail->next = mem_pool.free_head; 
  183.     mem_pool.free_head = block->node_head; 
  184.     mem_pool.free_cnt += cnt; 
  185.     /* increase the block count */ 
  186.     mem_pool.block_cnt++;    
  187.     return 1; 
  188. /* init the new block */ 
  189. static int mem_block_init(int cnt, mem_block_t *block) 
  190.     int size; 
  191.     mem_node_t *p; 
  192.       
  193.     if(block == NULL) 
  194.     { 
  195.     return 0; 
  196.     } 
  197.     size = cnt*sizeof(mem_node_t); 
  198.     if( (p = malloc(size)) == NULL) 
  199.     { 
  200.     fprintf(stderr, "mem_pool_init::malloc error/n"); 
  201.     return 0; 
  202.     } 
  203.     memset(p, 0, size); 
  204.     memset(block, 0, sizeof(mem_block_t)); 
  205.     block->node_cnt = cnt; 
  206.     block->node_head = p; 
  207.     block->node_tail = p+cnt-1; 
  208.     free_list_init(block); 
  209.     return 1; 
  210.  
  211. /* init free_list of the new block */ 
  212. static int free_list_init(const mem_block_t *block) 
  213.     mem_node_t *p, *end; 
  214.     if(block == NULL) 
  215.         { 
  216.     return 0; 
  217.     } 
  218.     /* start initiating free list */ 
  219.     end = block->node_tail; /* block_cnt > 0 */ 
  220.     for(p = block->node_head; p < end; p++) 
  221.     { 
  222.     p->next = (p+1); 
  223.     } 
  224.     p->next = NULL; /* end->next = NULL */ 
  225.     return 1; 
  226.  
  227. #ifdef MEM_POOL_DEBUG 
  228. #define ALLOC_COUNT 10 
  229. void alloc_test(char *ptr[]) 
  230.     int i, j; 
  231.     for(i = 0; i < ALLOC_COUNT; i++) 
  232.     { 
  233.     if( (ptr[i] = mem_alloc()) == NULL) 
  234.     { 
  235.         fprintf(stderr, "mem_alloc error/n"); 
  236.         return
  237.     } 
  238.     for(j = 0; j < ALLOC_COUNT; j++) 
  239.     { 
  240.         ptr[i][j] = 'a' + j; 
  241.     } 
  242.     } 
  243.     for(i = 0; i < ALLOC_COUNT; i++) 
  244.     { 
  245.     for(j = 0; j < ALLOC_COUNT; j++) 
  246.     { 
  247.         printf("ptr[%d][%d]=%c  ", i, j, ptr[i][j]); 
  248.     } 
  249.     fputc('/n', stdout); 
  250.     } 
  251.  
  252. int main(int argc, char *argv[]) 
  253.     int base, step; 
  254.     char *ptr1[ALLOC_COUNT], *ptr2[ALLOC_COUNT]; 
  255.   
  256.     switch(argc) 
  257.     { 
  258.     case 1: 
  259.         base = 0; /* default count */ 
  260.         step = 0; /* default count */ 
  261.         break
  262.     case 2: 
  263.         base = atoi(argv[1]); 
  264.         step = 0; 
  265.         break
  266.     case 3: 
  267.         base = atoi(argv[1]); 
  268.         step = atoi(argv[2]); 
  269.        break
  270.     default
  271.         fprintf(stderr, "Usage: %s [<base> [step]]/n", argv[0]); 
  272.         break
  273.     } 
  274.          
  275.         if(!mem_pool_init(base, step)) 
  276.     { 
  277.     fprintf(stderr, "mem_pool_init error/n"); 
  278.     return 1; 
  279.     } 
  280.     print_mem_pool_info(); 
  281.     alloc_test(ptr1); 
  282.     print_mem_pool_info(); 
  283.          
  284.     mem_free(ptr1[5]); 
  285.     print_mem_pool_info(); 
  286.          
  287.     alloc_test(ptr2); 
  288.     print_mem_pool_info(); 
  289.          
  290.     mem_pool_destroy(); 
  291.     /* once again */ 
  292.     if(!mem_pool_init(base, step)) 
  293.     { 
  294.     fprintf(stderr, "mem_pool_init error/n"); 
  295.     return 1; 
  296.     } 
  297.     print_mem_pool_info(); 
  298.     alloc_test(ptr1); 
  299.     print_mem_pool_info(); 
  300.          
  301.     mem_free(ptr1[5]); 
  302.  
  303.     print_mem_pool_info(); 
  304.     alloc_test(ptr2); 
  305.     print_mem_pool_info(); 
  306.     mem_pool_destroy(); 
  307.  
  308. #endif /* #ifdef MEM_POOL_DEBUG */ 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值