利用C/C++开发大型应用程序中,内存的管理与分配是一个需要认真考虑的部分。

本文描述了内存池设计原理并给出内存池的实现代码,代码支持Windows和Linux,多线程安全。

内存池设计过程中需要考虑好内存的分配与释放问题,其实也就是空间和时间的矛盾。

有的内存池设计得很巧妙,内存分配与需求相当,但是会浪费过多的时间去查找分配与释放,这就得不偿失;

实际使用中,我们更多的是关心内存分配的速度,而不是内存的使用效率。基于此,本文按照如下思想设计实现内存池。

主要包含三个结构:StiaticMemory, MemoryChunk和MemoryBlock,三者之间的关系如下图所示:

1.内存的分配:

(1)如果分配大小超过1024,直接采用malloc分配,分配的时候多分配sizeof(size_t)字节,用于保存该块的大小;

(2)否则根据分配大小,查找到容纳该大小的最小size的MemoryChunk;

(3)查找MemoryChunk的链表指针pList,找到空闲的MemoryBlock返回;

(4)如果pList为NULL,临时创建MemoryBlock返回;

(5)MemoryBlock头部包含两个成员,pChunk指向的所属的MemoryChunk对象,size表明大小,其后才是给用户使用的空间;

2.内存的释放:

(1)根据释放的指针,查找器size头部,即减去sizeof(size_t)字节,判断该块的大小;

(2)如果大小超过1024,直接free;

(3)否则交给MemoryChunk处理,而块的头部保存了该指针,因此直接利用该指针就可以收回该内存。

注意的问题:

上述设计的内存池通过冗余的头部来实现内存块的分配与释放,减少了内存池的操作时间,速度上要优于原始的malloc和free操作,同时减少了内存碎片的增加。

但是该设计中没有去验证释放的块冗余头部的正确性,因此故意释放不属于内存池中的块或者修改头部信息都会导致内存池操作失败,当然这些可以由程序员来控制。

此外,内存池中分配出去的内存块如果不主动释放,内存池没有保留信息,不会自动释放,但是在退出的时候会验证验证是否完全释放,其实这个在系统测试时候就可以检测出来,我想这个缺陷也是可以弥补的,在此提出,希望使用者注意。

下面贴上源码,如果对代码有任何建议或者发现存在的Bug,希望与我联系,共同学习交流,Tx。

MemoryChunk.h 文件,线程安全

[html] view plaincopyprint?
  1. #ifndef MEMORY_CHUNK_H
  2. #define MEMORY_CHUNK_H
  3. #include <cstdio>
  4. #include <cassert>
  5. #include <cstdlib>
  6. #ifdef WIN32
  7. #include <windows.h>
  8. typedef CRITICAL_SECTION MUTEXTYPE;
  9. #define INITMUTEX(hMutex) InitializeCriticalSection(&hMutex)
  10. #define DELMUTEX(hMutex) DeleteCriticalSection(&hMutex)
  11. #define LOCK(hMutex) EnterCriticalSection(&hMutex)
  12. #define UNLOCK(hMutex) LeaveCriticalSection(&hMutex)
  13. #else
  14. #include <pthread.h>
  15. typedef pthread_mutex_t MUTEXTYPE;
  16. #define INITMUTEX(hMutex) pthread_mutex_init(&hMutex,NULL)
  17. #define DELMUTEX(hMutex) pthread_mutex_destroy(&hMutex)
  18. #define LOCK(hMutex) pthread_mutex_lock(&hMutex)
  19. #define UNLOCK(hMutex) pthread_mutex_unlock(&hMutex)
  20. #endif
  21. class MemoryChunk;
  22. /** @struct MemoryBlock
  23. *
  24. */
  25. struct BlockHeader
  26. {
  27. MemoryChunk* pChunk;
  28. size_t len;
  29. };
  30. struct MemoryBlock;
  31. struct BlockData
  32. {
  33. union{
  34. MemoryBlock* pNext;
  35. char pBuffer;
  36. };
  37. };
  38. struct MemoryBlock
  39. {
  40. BlockHeader header;
  41. BlockData data;
  42. };
  43. /** @class MemoryChunk
  44. *
  45. */
  46. class MemoryChunk
  47. {
  48. public:
  49. MemoryChunk(size_t size, int count)
  50. {
  51. INITMUTEX(hMutex);
  52. this->pFreeList=NULL;
  53. this->size=size;
  54. this->count=0;
  55. MemoryBlock* pBlock;
  56. while(count--){
  57. pBlock=CreateBlock();
  58. if(!pBlock)break;
  59. pBlock->data.pNext=pFreeList;
  60. pFreeList=pBlock;
  61. }
  62. }
  63. ~MemoryChunk()
  64. {
  65. int tempcount=0;
  66. MemoryBlock* pBlock;
  67. while(pBlock=pFreeList){
  68. pFreeList=pBlock->data.pNext;
  69. DeleteBlock(pBlock);
  70. ++tempcount;
  71. }
  72. assert(tempcount==count);//!确保释放完全
  73. DELMUTEX(hMutex);
  74. }
  75. void* malloc()
  76. {
  77. MemoryBlock* pBlock;
  78. LOCK(hMutex);
  79. if(pFreeList){
  80. pBlock=pFreeList;
  81. pFreeList=pBlock->data.pNext;
  82. }
  83. else{
  84. if(!(pBlock=CreateBlock())){
  85. UNLOCK(hMutex);
  86. return NULL;
  87. }
  88. }
  89. UNLOCK(hMutex);
  90. return &pBlock->data.pBuffer;
  91. }
  92. static void free(void* pMem)
  93. {
  94. MemoryBlock* pBlock=(MemoryBlock*)((char*)pMem-sizeof(BlockHeader));
  95. pBlock->header.pChunk->free(pBlock);
  96. }
  97. void free(MemoryBlock* pBlock)
  98. {
  99. LOCK(hMutex);
  100. pBlock->data.pNext=pFreeList;
  101. pFreeList=pBlock;
  102. UNLOCK(hMutex);
  103. }
  104. MemoryChunk* Next(){return pNext;}
  105. protected:
  106. MemoryBlock* CreateBlock()
  107. {
  108. MemoryBlock* pBlock=(MemoryBlock*)::malloc(sizeof(BlockHeader)+size);
  109. if(pBlock){
  110. pBlock->header.pChunk=this;
  111. pBlock->header.len=size;
  112. ++count;
  113. }
  114. return pBlock;
  115. }
  116. void DeleteBlock(MemoryBlock* pBlock)
  117. {
  118. ::free(pBlock);
  119. }
  120. private:
  121. MemoryBlock* pFreeList;
  122. size_t size;//!Block大小
  123. int count;//!Block数目
  124. MemoryChunk* pNext;
  125. MUTEXTYPE hMutex;
  126. };
  127. #endif
#ifndef MEMORY_CHUNK_H
#define MEMORY_CHUNK_H
#include <cstdio>
#include <cassert>
#include <cstdlib>
#ifdef WIN32
#include <windows.h>
typedef CRITICAL_SECTION MUTEXTYPE;
#define INITMUTEX(hMutex) InitializeCriticalSection(&hMutex)
#define DELMUTEX(hMutex) DeleteCriticalSection(&hMutex)
#define LOCK(hMutex) EnterCriticalSection(&hMutex)
#define UNLOCK(hMutex) LeaveCriticalSection(&hMutex)
#else
#include <pthread.h>
typedef pthread_mutex_t MUTEXTYPE;
#define INITMUTEX(hMutex) pthread_mutex_init(&hMutex,NULL)
#define DELMUTEX(hMutex) pthread_mutex_destroy(&hMutex)
#define LOCK(hMutex) pthread_mutex_lock(&hMutex)
#define UNLOCK(hMutex) pthread_mutex_unlock(&hMutex)
#endif
class MemoryChunk;
/** @struct MemoryBlock
*
*/
struct BlockHeader
{
MemoryChunk* pChunk;
size_t len;
};
struct MemoryBlock;
struct BlockData
{
union{
MemoryBlock* pNext;
char pBuffer;
};
};
struct MemoryBlock
{
BlockHeader header;
BlockData data;
};
/** @class MemoryChunk
*
*/
class MemoryChunk
{
public:
MemoryChunk(size_t size, int count)
{
INITMUTEX(hMutex);
this->pFreeList=NULL;
this->size=size;
this->count=0;
MemoryBlock* pBlock;
while(count--){
pBlock=CreateBlock();
if(!pBlock)break;
pBlock->data.pNext=pFreeList;
pFreeList=pBlock;
}
}
~MemoryChunk()
{
int tempcount=0;
MemoryBlock* pBlock;
while(pBlock=pFreeList){
pFreeList=pBlock->data.pNext;
DeleteBlock(pBlock);
++tempcount;
}
assert(tempcount==count);//!确保释放完全
DELMUTEX(hMutex);
}
void* malloc()
{
MemoryBlock* pBlock;
LOCK(hMutex);
if(pFreeList){
pBlock=pFreeList;
pFreeList=pBlock->data.pNext;
}
else{
if(!(pBlock=CreateBlock())){
UNLOCK(hMutex);
return NULL;
}
}
UNLOCK(hMutex);
return &pBlock->data.pBuffer;
}
static void free(void* pMem)
{
MemoryBlock* pBlock=(MemoryBlock*)((char*)pMem-sizeof(BlockHeader));
pBlock->header.pChunk->free(pBlock);
}
void free(MemoryBlock* pBlock)
{
LOCK(hMutex);
pBlock->data.pNext=pFreeList;
pFreeList=pBlock;
UNLOCK(hMutex);
}
MemoryChunk* Next(){return pNext;}
protected:
MemoryBlock* CreateBlock()
{
MemoryBlock* pBlock=(MemoryBlock*)::malloc(sizeof(BlockHeader)+size);
if(pBlock){
pBlock->header.pChunk=this;
pBlock->header.len=size;
++count;
}
return pBlock;
}
void DeleteBlock(MemoryBlock* pBlock)
{
::free(pBlock);
}
private:
MemoryBlock* pFreeList;
size_t size;//!Block大小
int count;//!Block数目
MemoryChunk* pNext;
MUTEXTYPE hMutex;
};
#endif

StaticMemory.h文件,内存池对象

[html] view plaincopyprint?
  1. #ifndef STATIC_MEMORY_H
  2. #define STATIC_MEMORY_H
  3. #include "MemoryChunk.h"
  4. /** @ StaticMemory.h
  5. * 定义实现内存池
  6. * 采用固定大小策略进行内存管理与分配
  7. * 减少因大量小内存分配导致的内存碎片增加
  8. */
  9. struct HeapHeader
  10. {
  11. size_t size;
  12. };
  13. struct MemoryHeap
  14. {
  15. HeapHeader header;
  16. char pBuffer;
  17. };
  18. class StaticMemory
  19. {
  20. public:
  21. typedef enum{MAX_SIZE=1024,MIN_SIZE=sizeof(MemoryChunk*)};
  22. StaticMemory()
  23. {
  24. chunkcount=0;
  25. for(size_t size=MIN_SIZE; size<=MAX_SIZE; size*=2)++chunkcount;
  26. //pChunkList=(MemoryChunk**)malloc(sizeof(MemoryChunk*)*chunkcount);
  27. pChunkList=new MemoryChunk*[chunkcount];
  28. int index=0;
  29. for(size_t size=MIN_SIZE; size<=MAX_SIZE; size*=2)
  30. {
  31. pChunkList[index++]=new MemoryChunk(size,1000);
  32. }
  33. }
  34. ~StaticMemory()
  35. {
  36. for(int index=0; index<chunkcount; ++index)
  37. {
  38. delete pChunkList[index];
  39. }
  40. //free(pChunkList);
  41. delete[] pChunkList;
  42. }
  43. void* Malloc(size_t size)
  44. {
  45. if(size>MAX_SIZE){
  46. return malloc(size);
  47. }
  48. int index=0;
  49. for(size_t tsize=MIN_SIZE; tsize<=MAX_SIZE; tsize*=2){
  50. if(tsize>=size)break;
  51. ++index;
  52. }
  53. return pChunkList[index]->malloc();
  54. }
  55. void Free(void* pMem)
  56. {
  57. if(!free(pMem))MemoryChunk::free(pMem);
  58. }
  59. protected:
  60. void* malloc(size_t size)
  61. {
  62. MemoryHeap* pHeap=(MemoryHeap*)::malloc(sizeof(HeapHeader)+size);
  63. if(pHeap){
  64. pHeap->header.size=size;
  65. return &pHeap->pBuffer;
  66. }
  67. return NULL;
  68. }
  69. bool free(void* pMem)
  70. {
  71. MemoryHeap* pHeap=(MemoryHeap*)((char*)pMem-sizeof(HeapHeader));
  72. if(pHeap->header.size>MAX_SIZE){
  73. ::free(pHeap);
  74. return true;
  75. }
  76. return false;
  77. }
  78. private:
  79. MemoryChunk** pChunkList;
  80. int chunkcount;
  81. };
  82. #endif
#ifndef STATIC_MEMORY_H
#define STATIC_MEMORY_H
#include "MemoryChunk.h"
/** @ StaticMemory.h
* 定义实现内存池
* 采用固定大小策略进行内存管理与分配
* 减少因大量小内存分配导致的内存碎片增加
*/
struct HeapHeader
{
size_t size;
};
struct MemoryHeap
{
HeapHeader header;
char pBuffer;
};
class StaticMemory
{
public:
typedef enum{MAX_SIZE=1024,MIN_SIZE=sizeof(MemoryChunk*)};
StaticMemory()
{
chunkcount=0;
for(size_t size=MIN_SIZE; size<=MAX_SIZE; size*=2)++chunkcount;
//pChunkList=(MemoryChunk**)malloc(sizeof(MemoryChunk*)*chunkcount);
pChunkList=new MemoryChunk*[chunkcount];
int index=0;
for(size_t size=MIN_SIZE; size<=MAX_SIZE; size*=2)
{
pChunkList[index++]=new MemoryChunk(size,1000);
}
}
~StaticMemory()
{
for(int index=0; index<chunkcount; ++index)
{
delete pChunkList[index];
}
//free(pChunkList);
delete[] pChunkList;
}
void* Malloc(size_t size)
{
if(size>MAX_SIZE){
return malloc(size);
}
int index=0;
for(size_t tsize=MIN_SIZE; tsize<=MAX_SIZE; tsize*=2){
if(tsize>=size)break;
++index;
}
return pChunkList[index]->malloc();
}
void Free(void* pMem)
{
if(!free(pMem))MemoryChunk::free(pMem);
}
protected:
void* malloc(size_t size)
{
MemoryHeap* pHeap=(MemoryHeap*)::malloc(sizeof(HeapHeader)+size);
if(pHeap){
pHeap->header.size=size;
return &pHeap->pBuffer;
}
return NULL;
}
bool free(void* pMem)
{
MemoryHeap* pHeap=(MemoryHeap*)((char*)pMem-sizeof(HeapHeader));
if(pHeap->header.size>MAX_SIZE){
::free(pHeap);
return true;
}
return false;
}
private:
MemoryChunk** pChunkList;
int chunkcount;
};
#endif

ObejctManager.h文件,用于实现对象的创建与管理,比较简易。

[html] view plaincopyprint?
  1. #ifndef OBJECT_MANAGER_H
  2. #define OBJECT_MANAGER_H
  3. #include "StaticMemory.h"
  4. /** @class ObjectManager
  5. * 实现利用内存池创建对象
  6. * 要求对象具有缺省构造函数
  7. */
  8. template<typename T>
  9. class ObjectManager
  10. {
  11. public:
  12. typedef T ObjectType;
  13. static ObjectType* Create(StaticMemory* pool)
  14. {
  15. void* pobject=pool->Malloc(sizeof(T));
  16. new(pobject) ObjectType();
  17. return static_cast<ObjectType*>(pobject);
  18. }
  19. static void Delete(StaticMemory* pool, ObjectType* pobject)
  20. {
  21. pobject->~ObjectType();
  22. pool->Free(pobject);
  23. }
  24. };
  25. #endif
#ifndef OBJECT_MANAGER_H
#define OBJECT_MANAGER_H
#include "StaticMemory.h"
/** @class ObjectManager
* 实现利用内存池创建对象
* 要求对象具有缺省构造函数
*/
template<typename T>
class ObjectManager
{
public:
typedef T ObjectType;
static ObjectType* Create(StaticMemory* pool)
{
void* pobject=pool->Malloc(sizeof(T));
new(pobject) ObjectType();
return static_cast<ObjectType*>(pobject);
}
static void Delete(StaticMemory* pool, ObjectType* pobject)
{
pobject->~ObjectType();
pool->Free(pobject);
}
};
#endif

测试结果:

分单线程和多线程进行测试,重复的内存分配与释放在实际使用中是不太可能的,为了模拟实际使用,通过随机数来确定分配内存大小,同时也通过随机数来确定分配与释放操作。在测试过程中限制最大分配大小为1024,目的是为了测试小内存块的分配情况对比。

内存池单线程测试结果
分配与释放次数 malloc/free 内存池
                                                        100,000             0.01s         0.01s
                                                      1,000,000             0.15s         0.11s
                                                     10,000,000             1.26s         0.60s
                                                    100,000,000             9.21s         5.99s
                                                  1,000,000,000             92.70s         61.46s
内存池多线程测试结果
   线程数目                 malloc/free                       内存池
1/1,000,000                   0.15s                       0.10s
2/1,000,000                  1.49s                       0.73s
4/1,000,000                  9.945s                       6.71s
8/1,000,000                  45.60s                      28.82s

进行多线程测试主要是测试多线程运行下,加锁给内存分配带来的影响,因此为了排除CPU的影响,测试采用的机器为16盒,16G内存的Linux服务器。

具体配置如下:

Intel(R) Xeon(R) CPU           E5630  @ 2.53GHz

stepping        : 2
cpu MHz         : 2527.084

cache size      : 12288 KB

(转载)c++内存池实现 .相关推荐

  1. (转载)简单linux C++内存池

    C++代码 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ...

  2. 某内存池中的指针用法

    内存池实现有许多种,各有不同的优缺点. 这里不是主要说内存池,只是觉得这个内存池中的指针用得很飘逸! template <class T,int AllocSize = 50> class ...

  3. Nginx内存池实现的了解

    参考: http://blog.csdn.net/livelylittlefish/article/details/6586946 http://code.google.com/p/nginxsrp/ ...

  4. Python内存池管理与缓冲池设计

    出处:http://blog.csdn.net/zhzhl202/article/details/7547445#t4 Python是一门开发效率很高的语言,而且其既下里巴人,又阳春白雪.也就是说这门 ...

  5. LWIP再探----内存池管理

    这这里是接上一篇内存池管理部分的,这里如果读者一打开memp.c的话会感觉特别那一理解原作者在干嘛,但是看懂了就明白原作者是怎么巧妙的使用了宏.废话不多说先说了下我分析是一下宏的条件是 前提条件 ME ...

  6. 一个高效的内存池实现

    在高效C++编程中看到一个不错的内存池实现方案,这里共享下,大家看看有什么不足. 代码很简单,如下: template<typename T> class CMemoryPool {    ...

  7. 一种高效快速的内存池实现(附源码)

    此算法灵感来自于apache内存池实现原理,不过读者如果没有看过apache内存池实现也无关系,因为本算法相对apache内存池算法更为简单而且易懂,个人认为某些场合也更为高效,或许真正到了apach ...

  8. 自己做的一个固定大小对象内存池,效率大概为原始的new/delete的2倍

    提升不高,不过好处是可以多次申请小对象,一次释放.(只适应于无动态申请资源的class) vs2012测试情况如下: // CHchFixLenMemPool.h #pragma once #ifnd ...

  9. apr_pool -- 内存池

    这个指南主要介绍如何使用 libapr ( apache portable runtime ). 版权所有, Copyright (C) 2005 INOUE Seiichiro <inoue& ...

最新文章

  1. SBT搭建Spark
  2. 提高BSEG处理效率
  3. java中常见的几种内部类,你会几个?(未完)
  4. c语言倒置存放,c语言倒置
  5. 解耦,未解耦的区别_幂等与时间解耦之旅
  6. 从濒临解散到浴火重生,OceanBase 这十年经历了什么?
  7. java删除数组里的两个_java – 如何从两个数组列表中删除常用值
  8. 二叉树的之字形层序遍历
  9. python包的使用(一)——WordCloud词云
  10. jquery name选择器
  11. java语言排序函数_Java语言的8大排序
  12. SQL——查询和1002号的同学学习的课程完全相同的其他同学的学号和姓名
  13. python人工智能抠图_python实现人工智能Ai抠图功能
  14. java四则运算简单界面版
  15. tensorflow2.3版本 LSTM作为最后输出层 报错Function call stack: train_function -> train_function -> train_functio
  16. 苹果审核被拒1.1和5.0
  17. nodejs毕业设计源码大学生心理咨询微信小程序
  18. JS的 try catch使用心得
  19. adam优化_PyTorch 学习笔记(七):PyTorch的十个优化器
  20. 计算机视觉之迁移学习中的微调(fine tuning)

热门文章

  1. python一些常用方法_python 的一些常用方法
  2. cobbler安装和基本配置
  3. Maven中使用tomcat:run 出现错误 org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException...
  4. mysql闪退或者can not connect 127.0.0.1
  5. 【Beta阶段】第二次Scrum Meeting!
  6. android radiooptions简介
  7. linux内核中的GPIO系统之(2):pin control subsystem
  8. CTO俱乐部下午茶:技术团队管理中的那些事儿
  9. AWS服务器自动化迁移工具指南
  10. centos7.4 ngixn1.13.10 mysql5.7.21 php7.2.3 源码编译安装之后php无法连接mysql