C语言实现内存池 (转)

来源:互联网 发布:微信电子杂志制作软件 编辑:程序博客网 时间:2024/05/17 02:28

什么是内存池,这里简单介绍一下(不做详细说明),内存池技术是一种用于分配大量大小相同的小对象的技术,通过该技术可以极大加快内存分配/释放过程。其原理是先申请一大块内存,然后分成若干个大小相等的小块,用链表的方式将这些小块链在一起,当开发人员需要使用内存时(分配),从链表头取下一块返回给开发人员使用;当开发人员使用完毕后(释放),再将这块内存重新挂回链表尾。这样操作的好处有如下三点:1、提高分配和释放的效率;2、避免开发人员忘记释放内存造成内存泄露;3、减少内存占用(频繁的malloc是很占内存空间的,至于为什么我就不说了,可以到网上搜索内存管理相关的内容);

关于内存池技术的代码在网上也有不少,我也看过一些,有基于C现实的,也有C++实现的,但在这些文章里都发现两个问题,1、当开发人员使用完内存后,如果不释放,那么还是会有内存泄露的情况;2、在开发人员使用完内存后,释放的时候总会去循环判断该地址是否存在,在这种情况下,释放的效率并有没有得到提升。

那么如何解决这两个问题呢,我先简单介绍一下我这个内存池,先看段结构体:

[cpp] view plaincopyprint?
  1. typedef struct _memory_pool  
  2. {  
  3. unsigned int blockCount;//申请块数量   
  4. unsigned int blockCountStep;//内存块数增长步长  
  5. unsigned int blockSize;//单个块的大小   
  6. unsigned int freeCount;//空闲的内存块数  
  7. MemoryBlock *freeHead; //空闲的头   
  8. MemoryBlock *freeTail; //空闲的尾   
  9. MemoryBlock *usedHead; //已使用的头   
  10. MemoryBlock *usedTail; //已使用的尾   
  11. char *pBlockMemoryHead; //块的头指针,用于释放内存时候用(因为块的分配了一大块的内存)  
  12. char *pDataMemoryHead;//数据区域头指针   
  13. } MemoryPool;  
typedef struct _memory_pool { unsigned int blockCount;//申请块数量 unsigned int blockCountStep;//内存块数增长步长 unsigned int blockSize;//单个块的大小 unsigned int freeCount;//空闲的内存块数 MemoryBlock *freeHead; //空闲的头 MemoryBlock *freeTail; //空闲的尾 MemoryBlock *usedHead; //已使用的头 MemoryBlock *usedTail; //已使用的尾 char *pBlockMemoryHead; //块的头指针,用于释放内存时候用(因为块的分配了一大块的内存) char *pDataMemoryHead;//数据区域头指针 } MemoryPool;

 

这里面描述了详细存放信息,当池初始化时,所有块都存在空闲块中,已使用块为空,当申请一块空间时,从空闲块的头取下来放到已使用的块中,基本过程就是这样子的。下面来解决上面提到的两个问题,1、在内存泄露方面,先申请两大块的连续空间,一块用于存放块的基本信息(块链表),另一块返回给开发人员使用(数据区域),然后用指针保存两块内存地址,这样一来,不管你是否释放,在程序需要清理内存的时候,我只需要free两次;2、在释放效率方面,我们不使用循环方式来处理,而是在返回给开发人员使用的内存块前面加4个字节存放与他关联的块信息块地址,在释放的时候,我们只需要(MemoryBlock *)((char *)ptr – 4)就能得到块地址,这样就很方便的挂回空闲块。具体现实代码如下:

[cpp] view plaincopyprint?
  1. #include <stdio.h>   
  2. #include <malloc.h>   
  3. #include <string.h>   
  4.    
  5. typedef struct _memory_block  
  6. {  
  7. struct _memory_block *pNext; //下一个内存单元  
  8. struct _memory_block *pPrev; //上一个内存单元  
  9. char* data; //数据,   
  10. } MemoryBlock;  
  11.    
  12. typedef struct _memory_pool  
  13. {  
  14. unsigned int blockCount;//申请块数量   
  15. unsigned int blockCountStep;//内存块数增长步长  
  16. unsigned int blockSize;//单个块的大小   
  17. unsigned int freeCount;//空闲的内存块数  
  18. MemoryBlock *freeHead; //空闲的头   
  19. MemoryBlock *freeTail; //空闲的尾   
  20. MemoryBlock *usedHead; //已使用的头   
  21. MemoryBlock *usedTail; //已使用的尾   
  22. char *pBlockMemoryHead; //块的头指针,用于释放内存时候用(因为块的分配了一大块的内存)  
  23. char *pDataMemoryHead;//数据区域头指针   
  24. } MemoryPool;  
  25.    
  26. int Xpool_init(unsigned int blockCount, unsigned int blockSize);  
  27. int Xpool_destroy(void);  
  28. void* Xpool_alloc(unsigned int size);  
  29. int Xpool_free(void *ptr);  
  30.    
  31. static int Xpool_block(unsigned int blockCount, unsigned int blockSize);  
  32. static MemoryPool memory;  
  33.    
  34. //初始化内存池   
  35. int Xpool_init(unsigned int blockCount, unsigned int blockSize)  
  36. {  
  37. MemoryPool *p = &memory;  
  38. p->blockCount = blockCount;  
  39. p->blockSize = blockSize;  
  40. p->freeCount = blockCount;  
  41. p->blockCountStep = 100;  
  42. p->freeHead = p->freeTail = NULL;  
  43. p->usedHead = p->usedTail = NULL;  
  44.    
  45. Xpool_block(blockCount, blockSize);  
  46. return 0;  
  47. }  
  48.    
  49. //申请块,并且把新申请的块连到空闲块后面   
  50. static int Xpool_block(unsigned int blockCount, unsigned int blockSize)  
  51. {  
  52. MemoryPool *p = &memory;  
  53. MemoryBlock *pFree = NULL;//空闲块连表指针   
  54.    
  55. p->pBlockMemoryHead = (char *)malloc(sizeof(MemoryBlock) * blockCount);//分配一大块连续的内存块空间存放块信息  
  56. p->pDataMemoryHead = (char *)malloc((blockSize + sizeof(MemoryBlock *)) * blockCount);//分配一大块连续的内存空间存放供用户使用的空间  
  57.    
  58. for(unsigned int i = 0; i < blockCount; i++)  
  59. {  
  60. pFree = (MemoryBlock *)(p->pBlockMemoryHead + (sizeof(MemoryBlock) * i));//(MemoryBlock *)malloc(sizeof(MemoryBlock));  
  61. pFree->data = p->pDataMemoryHead + ((blockSize + sizeof(MemoryBlock *)) * i);//(void *)malloc(blockSize + sizeof(MemoryBlock *));//分配一块数据区域  
  62. pFree->pNext = NULL;  
  63. pFree->pPrev = p->freeTail;  
  64.    
  65. if(p->freeHead == NULL){  
  66. p->freeHead = p->freeTail = pFree;  
  67. }else{  
  68. p->freeTail->pNext = pFree;  
  69. p->freeTail = pFree;  
  70. }  
  71. }  
  72.    
  73. return 0;  
  74. }  
  75.    
  76. //销毁内存池   
  77. int Xpool_destroy(void)  
  78. {  
  79. MemoryPool *p = &memory;  
  80.    
  81. //释放内存块所占的内存   
  82. free(p->pBlockMemoryHead);  
  83.    
  84. //释放数据区域所占的内存   
  85. free(p->pDataMemoryHead);  
  86.    
  87. return 0;  
  88. }  
  89.    
  90. //申请内存   
  91. void* Xpool_alloc(unsigned int size)  
  92. {  
  93. MemoryPool *p = &memory;  
  94. MemoryBlock *block = NULL;  
  95.    
  96. if(p->freeHead == NULL){//没有可用空间  
  97. Xpool_block(p->blockCountStep, p->blockSize);  
  98. }  
  99.    
  100. block = p->freeHead;//获取表头内存块   
  101. p->freeHead = block->pNext;//将空闲块的链表头   
  102. p->freeCount--;//空闲块数量减一   
  103. block->pNext = NULL;  
  104. block->pPrev = p->usedTail;//这个块的上个块是已使用块的最后一个块   
  105.    
  106. //第一次使用内存?   
  107. if(p->usedHead == NULL){  
  108. p->usedHead = p->usedTail = block;//,则已使用的头和尾都指向这个块   
  109. }else{//不是第一次   
  110. p->usedTail->pNext = block;  
  111. p->usedTail = block;  
  112. }  
  113. //留下data里一个指针的空间,用于保存与数据关联的块地址   
  114.    
  115. block->data = (char *)block;  
  116. return (char *)block->data + sizeof(MemoryBlock *);  
  117. }  
  118.    
  119. //回收内存   
  120. int Xpool_free(void *ptr)  
  121. {  
  122. MemoryPool *p = &memory;  
  123. char *realptr = (char *)ptr - sizeof(MemoryBlock *); //数据块真实的起始地址  
  124. MemoryBlock *block = (MemoryBlock *)realptr;  
  125.    
  126. if(block == NULL){  
  127. return NULL;  
  128. }  
  129.    
  130. if(block->pPrev == NULL){//如果是头   
  131. p->usedHead = block->pNext;  
  132. if(p->usedHead != NULL){  
  133. p->usedHead->pPrev = NULL;  
  134. }  
  135. }else if(block->pNext == NULL){//如果是尾  
  136. p->usedTail = block->pPrev;  
  137. if(p->usedTail != NULL){  
  138. p->usedTail->pNext = NULL;  
  139. }  
  140. }else{//中间的   
  141. block->pPrev->pNext = block->pNext;  
  142. block->pNext->pPrev = block->pPrev;  
  143. }  
  144.    
  145. //重置参数   
  146. block->pPrev = p->freeTail;  
  147. block->pNext = NULL;  
  148. block->data = realptr;  
  149.    
  150. //加到空闲块链表   
  151. p->freeTail->pNext = block;  
  152. p->freeTail = block;  
  153. p->freeCount++;  
  154.    
  155. return 0;  
  156. }  
  157.    
  158. int main(int argc, char *argv[])  
  159. {  
  160. Xpool_init(10, 96);  
  161. char *p = (char *)Xpool_alloc(20);  
  162. Xpool_free(p);  
  163. Xpool_destroy();  
  164. return 0;  
  165. }  

原创粉丝点击