linux c++ 内存池的简单实现
http://www.codeproject.com/KB/cpp/MemoryPool.aspx
http://www.cnblogs.com/rosesmall/archive/2012/04/27/2473931.html
译者点评:一个简单的内存池实现,附有源码,简单易懂,适合入门。
概述
在c/c++中,内存分配(如malloc或new)会使用很多时间。
一个程序会随着长时间的运行和内存的申请释放而变得越来越慢,内存也会随着时间逐渐碎片化。特别是高频率的进行小内存申请释放,此问题变得尤其严重。
解决方案:定制内存池
为解决上述问题,一个(可能的)的解决方案就是使用内存池。
“内存池”在初始化时,分配一个大块内存(称 原始内存块),并且将此内存分割为一些小的内存块。当你需要请求分配内存时,则从内存池中取出事先分配好的内存,而不是向OS申请。内存池最大的优势在于:
1、极少的(甚至没有)堆碎片整理
2、较之普通内存分配(如malloc,new),有着更快的速度
额外的,你还将获得如下好处:
1、检测任意的指针是否指向内存池内
2、生成"heap-dump"
3、各种 内存泄漏 检测:当你没有释放之前申请的内存,内存池将抛出断言
如何工作?
让我们看看内存池的UML模型图:
图中简要的描述了CMemoryPool class,更多的细节请查看源码中class声明。
那么,CMemoryPool如何实际工作?
关于 MemoryChunks
正如你在UML图中所看到的,内存池维护着一个SMemoryChunk链表,并管理着三个指向SMemoryChunk结构的指针(m_ptrFirstChunk
, m_ptrLastChunk
, and m_ptrCursorChunk
)。这些指针指向SMemoryChunk链表的不同位置。让我们更深入的观察
SMemoryChunk:(在内存池实现中,SMemoryChunk封装了原始内存块的各个部分 -- 译者注)
typedef struct SMemoryChunk
{
TByte *Data ; // 常规数据指针
std::size_t DataSize ; // 内存块容量
std::size_t UsedSize ; // 内存块当前使用大小
bool IsAllocationChunk ; // 为true时, 内存块已被分配,可用free之类的函数释放
SMemoryChunk *Next ; // 指向内存块链表中的下一个内存块,可能为null
第一步:预分配内存
当你调用CMemoryPool的构造函数,内存池会向OS申请原始内存块。
/******************
Constructor
******************/
CMemoryPool::CMemoryPool(const std::size_t &sInitialMemoryPoolSize,
const std::size_t &sMemoryChunkSize,
const std::size_t &sMinimalMemorySizeToAllocate,
bool bSetMemoryData)
{
m_ptrFirstChunk = NULL ;
m_ptrLastChunk = NULL ;
m_ptrCursorChunk = NULL ;
m_sTotalMemoryPoolSize = 0 ;
m_sUsedMemoryPoolSize = 0 ;
m_sFreeMemoryPoolSize = 0 ;
m_sMemoryChunkSize = sMemoryChunkSize ;
m_uiMemoryChunkCount = 0 ;
m_uiObjectCount = 0 ;
m_bSetMemoryData = bSetMemoryData ;
m_sMinimalMemorySizeToAllocate = sMinimalMemorySizeToAllocate ;
// Allocate the Initial amount of Memory from the Operating-System...
AllocateMemory(sInitialMemoryPoolSize) ;
}
所有的成员的函数初始化在此完成,最后AllocateMemory将完成向OS申请原始内存块的任务。
/******************
AllocateMemory
******************/
<CODE>bool CMemoryPool::AllocateMemory(const std::size_t &sMemorySize)
{
std::size_t sBestMemBlockSize = CalculateBestMemoryBlockSize(sMemorySize) ;
// allocate from Operating System
TByte *ptrNewMemBlock = (TByte *) malloc(sBestMemBlockSize) ;
...
那么,内存池如何来管理这些数据呢?
第二步:内存分块
回忆前述,内存池管理使用SMemoryChunk链表来管理数据。在向OS申请原始内存块后,
我们还没有在其上建立SMemoryChunk。
图中所示的为初始化分配后的内存池。
我们需要分配一组SMemoryChunk,用于管理原始内存块:
//(AllocateMemory() continued) :
...
unsigned int uiNeededChunks = CalculateNeededChunks(sMemorySize) ;
// allocate Chunk-Array to Manage the Memory
SMemoryChunk *ptrNewChunks =
(SMemoryChunk *) malloc((uiNeededChunks * sizeof(SMemoryChunk))) ;
assert(((ptrNewMemBlock) && (ptrNewChunks))
&& "Error : System ran out of Memory") ;
...
CalculateNeededChunks函数用于计算需要分配的SMemoryChunk的数量。分配后,ptrNewChunks指向这组SMemoryChunk。注意,SMemoryChunk中目前只是持有垃圾数据,我们还没有为SMemoryChunk的成员关联至原始内存块。
最后,AllocateMemory函数将为所有的SMemoryChunk关联至原始内存块。
//(AllocateMemory() continued) :
...
// Associate the allocated Memory-Block with the Linked-List of MemoryChunks
return LinkChunksToData(ptrNewChunks, uiNeededChunks, ptrNewMemBlock) ;
让我们进入LinkChunksToData中一窥究竟:
/******************
LinkChunksToData
******************/
bool CMemoryPool::LinkChunksToData(SMemoryChunk *ptrNewChunks,
unsigned int uiChunkCount, TByte *ptrNewMemBlock)
{
SMemoryChunk *ptrNewChunk = NULL ;
unsigned int uiMemOffSet = 0 ;
bool bAllocationChunkAssigned = false ;
for(unsigned int i = 0; i < uiChunkCount; i++)
{
if(!m_ptrFirstChunk)
{
m_ptrFirstChunk = SetChunkDefaults(&(ptrNewChunks[0])) ;
m_ptrLastChunk = m_ptrFirstChunk ;
m_ptrCursorChunk = m_ptrFirstChunk ;
}
else
{
ptrNewChunk = SetChunkDefaults(&(ptrNewChunks[i])) ;
m_ptrLastChunk->Next = ptrNewChunk ;
m_ptrLastChunk = ptrNewChunk ;
}
uiMemOffSet = (i * ((unsigned int) m_sMemoryChunkSize)) ;
m_ptrLastChunk->Data = &(ptrNewMemBlock[uiMemOffSet]) ;
// 第一个SMemoryChunk被称为“AllocationChunk”。
// 这意味着,它持有原始内存块的指针并能够利用它释放原始内存块
if(!bAllocationChunkAssigned)
{
m_ptrLastChunk->IsAllocationChunk = true ;
bAllocationChunkAssigned = true ;
}
}
return RecalcChunkMemorySize(m_ptrFirstChunk, m_uiMemoryChunkCount) ;
}
让我们一步步的来看这个重要的函数:第一行检查在SMemoryChunk链表中是否已经有了可用的
SMemoryChunk:
...
if(!m_ptrFirstChunk)
...
在最初始进入循环,此条件不成立。那么,我们为一些内部的成员进行关联。
...
m_ptrFirstChunk = SetChunkDefaults(&(ptrNewChunks[0])) ;
m_ptrLastChunk = m_ptrFirstChunk ;
m_ptrCursorChunk = m_ptrFirstChunk ;
...
m_ptrFirstChunk这时指向SMemoryChunk中的第一个元素。每一个SMemoryChunk管理的内存块大小由m_sMemoryChunkSize指定。这些内存块来自于原始内存块,偏移量
uiMemOffSet指示着每一个SMemoryChunk所管理的内存起始点处于原始内存块的何处。
uiMemOffSet = (i * ((unsigned int) m_sMemoryChunkSize)) ;
m_ptrLastChunk->Data = &(ptrNewMemBlock[uiMemOffSet]) ;
额外的,每个新的SMemoryChunk都将被指定为新的m_ptrLastChunk。
...
m_ptrLastChunk->Next = ptrNewChunk ;
m_ptrLastChunk = ptrNewChunk ;
...
经过循环之后,内存池中的SMemoryChunk链表将被成功的与原始内存块关联。
最终,我们重新计算每一个SMemoryChunk能管理到的内存尺寸。这个步骤相当耗时,并且必须在每次从OS附加新的内存到内存池后调用。所有被计算出的尺寸,将被DataSize成员持有。
/******************
RecalcChunkMemorySize
******************/
bool CMemoryPool::RecalcChunkMemorySize(SMemoryChunk *ptrChunk,
unsigned int uiChunkCount)
{
unsigned int uiMemOffSet = 0 ;
for(unsigned int i = 0; i < uiChunkCount; i++)
{
if(ptrChunk)
{
uiMemOffSet = (i * ((unsigned int) m_sMemoryChunkSize)) ;
ptrChunk->DataSize =
(((unsigned int) m_sTotalMemoryPoolSize) - uiMemOffSet) ;
ptrChunk = ptrChunk->Next ;
}
else
{
assert(false && "Error : ptrChunk == NULL") ;
return false ;
}
}
return true ;
}
在RecalcChunkMemorySize之后,每一个SMemoryChunk将知道自己需要释放多大的内存。因此,这使得 确定某个SMemoryChunk能否持有一个指定大小的内存 将变得非常容易:当DataSize
成员大于或等于请求的内存尺寸并且UsedSize
成员值为0,这时此SMemoryChunk将能够满足用户的需要。让我们来看一个具体的例子来加深对这个机制的理解,假设内存池为600字节,并且每个SMemoryChunk为100字节。
第三步:向内存池请求内存
现在,如果用户向内存池请求内存,那会发生什么呢?最开始,所有的SMemoryChunk在内存池中都是闲置可用状态:
让我们看看GetMemory函数吧:
/******************
GetMemory
******************/
void *CMemoryPool::GetMemory(const std::size_t &sMemorySize)
{
std::size_t sBestMemBlockSize = CalculateBestMemoryBlockSize(sMemorySize) ;
SMemoryChunk *ptrChunk = NULL ;
while(!ptrChunk)
{
// 搜索是否有符合条件的SMemoryChunk?
ptrChunk = FindChunkSuitableToHoldMemory(sBestMemBlockSize) ;
if(!ptrChunk)
{
// 没有SMemoryChunk符合条件
// 内存池太小了,需要向OS申请新的内存
sBestMemBlockSize = MaxValue(sBestMemBlockSize, CalculateBestMemoryBlockSize(m_sMinimalMemorySizeToAllocate)) ;
AllocateMemory(sBestMemBlockSize) ;
}
}
// 一个合适的SMemoryChunk被找到
// 校正其 TotalSize/UsedSize 成员的值
m_sUsedMemoryPoolSize += sBestMemBlockSize ;
m_sFreeMemoryPoolSize -= sBestMemBlockSize ;
m_uiObjectCount++ ;
SetMemoryChunkValues(ptrChunk, sBestMemBlockSize) ;
// 最终将内存指针返回给用户
return ((void *) ptrChunk->Data) ;
}
当用户向内存池发出请求,内存池搜索SMemoryChunk链表,并在其中找到满足条件的SMemoryChunk,“满足条件”意味着:
1、DataSize必须大于或等于请求的大小
2、UsedSize必须为0
FindChunkSuitableToHoldMemory
如果其返回NULL,那么就表示在内存池中没有可用的内存。这将会引发AllocateMemory函数的调用(前述),此函数会向OS申请更多的内存。
如果返回非NULL,那么便找到了可用的SMemoryChunk。
示例
假设,用户向内存池申请250字节:
如你所见,每一个SMemoryChunk管理100字节,所以,250字节并不是100的整数倍。这会引发什么情况呢?GetMemory
将会返回指向第一个SMemoryChunk的指针,并设置其的UsedSize成员为300字节,因为300是100的整数倍数值中最小的,并且其大于250。多出的50字节称为"memory overhead".
当FindChunkSuitableToHoldMemory
寻找可用的SMemoryChunk时,它将只会从一个闲置的SMemoryChunk跳到另一个闲置的SMemoryChunk。这意味着,如果又有申请内存的请求达到,例子中的第四个SMemoryChunk将是寻找的起始点。
如何使用代码
代码的使用简单而直接:
只需要在你的程序中包含"CMemoryPool.h",并附加源码文件至你的IDE/makefile:
- CMemoryPool.h
- CMemoryPool.cpp
- IMemoryBlock.h
- SMemoryChunk.h
你需要创建一个CMemoryPool实例,并从中分配内存。所有的内存池配置都在CMemoryPool的构造函数中被完成。
使用示例
MemPool::CMemoryPool *g_ptrMemPool = new MemPool::CMemoryPool() ;
char *ptrCharArray = (char *) g_ptrMemPool->GetMemory(100) ;
...
g_ptrMemPool->FreeMemory(ptrCharArray, 100) ;
delete g_ptrMemPool ;
兴趣点
内存诊断
你可以调用WriteMemoryDumpToFile函数来输出内存诊断信息文件。让我们看下源码附带的MyTestClass_OPOverload类的构造函数。(此类重载了new和delete操作,使用了内存池操作)
MyTestClass_OPOverload()
{
m_cMyArray[0] = 'H' ;
m_cMyArray[1] = 'e' ;
m_cMyArray[2] = 'l' ;
m_cMyArray[3] = 'l' ;
m_cMyArray[4] = 'o' ;
m_cMyArray[5] = NULL ;
m_strMyString = "This is a small Test-String" ;
m_iMyInt = 12345 ;
m_fFloatValue = 23456.7890f ;
m_fDoubleValue = 6789.012345 ;
Next = this ;
}
MyTestClass *ptrTestClass = new MyTestClass ;
g_ptrMemPool->WriteMemoryDumpToFile("MemoryDump.bin") ;
让我们看看内存诊断文件的内容:
如你所见,这是MyTestClass_OPOverload所有的成员在内存中的表示。
速度测试
我在windows下完成了一个简单的速度测试(使用timeGetTime()),结果显示内存池的使用可以大大增加程序的速度。所有的测试均使用vs2003,debug模式编译(测试机器:Intel Pentium IV Processor (32 bit), 1GB RAM, MS Windows XP Professional)
//Array-test (Memory Pool):
for(unsigned int j = 0; j < TestCount; j++)
{
// ArraySize = 1000
char *ptrArray = (char *) g_ptrMemPool->GetMemory(ArraySize) ;
g_ptrMemPool->FreeMemory(ptrArray, ArraySize) ;
}
//Array-test (Heap):
for(unsigned int j = 0; j < TestCount; j++)
{
// ArraySize = 1000
char *ptrArray = (char *) malloc(ArraySize) ;
free(ptrArray) ;
}
//Class-Test for MemoryPool and Heap (重载了new与delete)
for(unsigned int j = 0; j < TestCount; j++)
{
MyTestClass *ptrTestClass = new MyTestClass ;
delete ptrTestClass ;
}
关于代码
代码在ms windows与linux的如下c++编译器通过测试:
- Microsoft Visual C++ 6.0
- Microsoft Visual C++ .NET 2003
- MinGW (GCC) 3.4.4 (Windows)
- GCC 4.0.X (Debian GNU Linux)
vc6.0的项目文件与vs2003的项目文件已经包含在源码中。在64位的环境下使用应该没有问题。
注意:此内存池并非线程安全的。
待办事项
此内存池实现远远不够完善,待办事项如下:
1、对于海量的内存,memory overhead可能很大
2、一些CalculateNeededChunks
函数的调用可以通过重构某些函数来被剥离,之后速度可能会更快。
3、更多的稳定性测试(尤其是对长时间运行的程序)
4、线程安全的实现
以下代码是在linux环境下编译调试过的:
BasicIncludes.h
1 /****************** 2 BasicIncludes.h 3 ******************/ 4 5 /*!\file BasicIncludes.h 6 * \brief Contains some Basic Include-files used almost everywhere 7 * (like iostream, assert, stdlib, etc.). 8 */ 9 10 #ifndef __INC_BasicIncludes_h__ 11 #define __INC_BasicIncludes_h__ 12 13 #include <stdlib.h> 14 #include <stdio.h> 15 #include <math.h> 16 #include <assert.h> 17 18 #include <iostream> 19 #include <fstream> 20 21 // for MSVC++ 6.0 22 /* 23 namespace std 24 { 25 typedef unsigned int size_t ; 26 } 27 */ 28 29 #endif /* __INC_BasicIncludes_h__ */
IMemoryBlock.h
1 /****************** 2 IMemoryBlock.h 3 ******************/ 4 5 /*!\file IMemoryBlock.h 6 * \brief Contains the "IMemoryBlock" Class-defintion. 7 * This is the (abstract) interface for the actual MemoryPool-Class. 8 */ 9 10 11 #ifndef __INC_IMemoryBlock_h__ 12 #define __INC_IMemoryBlock_h__ 13 14 #include "../BasicIncludes.h" 15 16 /*!\namespace MemPool 17 * \brief MemoryPool Namespace 18 * 19 * This Namespace contains all classes and typedefs needed by 20 * the MemoryPool implementation. 21 * The MemoryPool has its own namespace because some typedefs 22 * (e.g. TByte) may intefer with other toolkits if the 23 * MemoryPool would be in the global namespace. 24 */ 25 namespace MemPool 26 { 27 28 /*!\typedef unsigned char TByte ; 29 * \brief Byte (= 8 Bit) Typedefinition. 30 */ 31 typedef unsigned char TByte ; 32 33 /*!\class IMemoryBlock 34 * \brief Interface Class (pure Virtual) for the MemoryPool 35 * 36 * Abstract Base-Class (interface) for the MemoryPool. 37 * Introduces Basic Operations like Geting/Freeing Memory. 38 */ 39 class IMemoryBlock 40 { 41 public : 42 virtual ~IMemoryBlock() {} ; 43 44 virtual void *GetMemory(const std::size_t &sMemorySize) = 0 ; 45 virtual void FreeMemory(void *ptrMemoryBlock, const std::size_t &sMemoryBlockSize) = 0 ; 46 } ; 47 48 } 49 #endif /* __INC_IMemoryBlock_h__ */
SMemoryChunk.h
1 /****************** 2 SMemoryChunk.h 3 ******************/ 4 5 /*!\file SMemoryChunk.h 6 * \brief Contains the "SMemoryChunk" Type-definition. 7 */ 8 9 #ifndef __INC_SMemoryChunk_h__ 10 #define __INC_SMemoryChunk_h__ 11 12 #include "IMemoryBlock.h" 13 14 namespace MemPool 15 { 16 17 /*!\class SMemoryChunk 18 * \brief Memory Chunk Struct 19 * 20 * This struct will hold (and manage) the actual allocated Memory. 21 * Every MemoryChunk will point to a MemoryBlock, and another SMemoryChunk, 22 * thus creating a linked-list of MemoryChunks. 23 */ 24 typedef struct SMemoryChunk 25 { 26 TByte *Data ; //!< The actual Data 27 std::size_t DataSize ; //!< Size of the "Data"-Block 28 std::size_t UsedSize ; //!< actual used Size 29 bool IsAllocationChunk ; //!< true, when this MemoryChunks Points to a "Data"-Block which can be deallocated via "free()" 30 SMemoryChunk *Next ; //!< Pointer to the Next MemoryChunk in the List (may be NULL) 31 32 } SMemoryChunk ; 33 34 } 35 36 #endif /* __INC_SMemoryChunk_h__ */
CMemoryPool.h
1 /****************** 2 CMemoryPool.h 3 ******************/ 4 5 /*!\file CMemoryPool.h 6 * \brief Contains the "CMemoryPool" Class-defintion. 7 */ 8 9 #ifndef __INC_CMemoryPool_h__ 10 #define __INC_CMemoryPool_h__ 11 12 #include "IMemoryBlock.h" 13 #include "SMemoryChunk.h" 14 15 namespace MemPool 16 { 17 18 static const std::size_t DEFAULT_MEMORY_POOL_SIZE = 1000 ; //!< Initial MemoryPool size (in Bytes) 19 static const std::size_t DEFAULT_MEMORY_CHUNK_SIZE = 128 ; //!< Default MemoryChunkSize (in Bytes) 20 static const std::size_t DEFAULT_MEMORY_SIZE_TO_ALLOCATE = DEFAULT_MEMORY_CHUNK_SIZE * 2 ; //!< Default Minimal Memory-Size (in Bytes) to Allocate. 21 22 /*!\class CMemoryPool 23 * \brief MemoryPool-Class 24 * 25 * This class is the actual implementation of the IMemoryBlock - Interface. 26 * It is responsible for all MemoryRequests (GetMemory() / FreeMemory()) and 27 * manages the allocation/deallocation of Memory from the Operating-System. 28 */ 29 class CMemoryPool : public IMemoryBlock 30 { 31 public : 32 /*! 33 Contructor 34 \param [IN] sInitialMemoryPoolSize The Initial Size (in Bytes) of the Memory Pool 35 \param [IN] sMemoryChunkSize The Size (in Bytes) each MemoryChunk can Manage. 36 A low sMemoryChunkSize increases the MemoryPool runtime (bad), but decreases the Memory-overhead/fragmentation (good) 37 \param [IN] sMinimalMemorySizeToAllocate The Minimal amount of Memory which is allocated (in Bytes). 38 That means, every time you have to allocate more Memory from the Operating-System, 39 <b>at least</b> sMinimalMemorySizeToAllocate Bytes are allocated. 40 When you have to request small amount of Memory very often, this will speed up 41 the MemoryPool, beacause when you allocate a new Memory from the OS, 42 you will allocate a small "Buffer" automatically, wich will prevent you from 43 requesting OS-memory too often. 44 \param [IN] bSetMemoryData Set to true, if you want to set all allocated/freed Memory to a specific 45 Value. Very usefull for debugging, but has a negativ impact on the runtime. 46 */ 47 CMemoryPool(const std::size_t &sInitialMemoryPoolSize = DEFAULT_MEMORY_POOL_SIZE, 48 const std::size_t &sMemoryChunkSize = DEFAULT_MEMORY_CHUNK_SIZE, 49 const std::size_t &sMinimalMemorySizeToAllocate = DEFAULT_MEMORY_SIZE_TO_ALLOCATE, 50 bool bSetMemoryData = false) ; 51 virtual ~CMemoryPool() ; //!< Destructor 52 53 /*! 54 Get "sMemorySize" Bytes from the Memory Pool. 55 \param [IN] sMemorySize Sizes (in Bytes) of Memory. 56 \return Pointer to a Memory-Block of "sMemorySize" Bytes, or NULL if an error occured. 57 */ 58 virtual void *GetMemory(const std::size_t &sMemorySize) ; 59 60 /*! 61 Free the allocated memory again.... 62 \param [IN] ptrMemoryBlock Pointer to a Block of Memory, which is to be freed (previoulsy allocated via "GetMemory()"). 63 \param [IN] sMemorySize Sizes (in Bytes) of Memory. 64 */ 65 virtual void FreeMemory(void *ptrMemoryBlock, const std::size_t &sMemoryBlockSize) ; 66 67 /*! 68 Writes the contents of the MemoryPool to a File. 69 Note : This file can be quite large (several MB). 70 \param [IN] strFileName FileName of the MemoryDump. 71 \return true on success, false otherwise 72 */ 73 bool WriteMemoryDumpToFile(const std::string &strFileName) ; 74 /*! 75 Check, if a Pointer is in the Memory-Pool. 76 Note : This Checks only if a pointer is inside the Memory-Pool, 77 and <b>not</b> if the Memory contains meaningfull data. 78 \param [IN] ptrPointer Pointer to a Memory-Block which is to be checked. 79 \return true, if the Pointer could be found in the Memory-Pool, false otherwise. 80 */ 81 bool IsValidPointer(void *ptrPointer) ; 82 83 private : 84 /*! 85 Will Allocate <b>at least</b> "sMemorySize" Bytes of Memory from the Operating-System. 86 The Memory will be cut into Pieces and Managed by the MemoryChunk-Linked-List. 87 (See LinkChunksToData() for details). 88 \param [IN] sMemorySize The Memory-Size (in Bytes) to allocate 89 \return true, if the Memory could be allocated, false otherwise (e.g. System is out of Memory, etc.) 90 */ 91 bool AllocateMemory(const std::size_t &sMemorySize) ; 92 void FreeAllAllocatedMemory() ; //!< Will free all Aloocated Memory to the Operating-System again. 93 94 unsigned int CalculateNeededChunks(const std::size_t &sMemorySize) ; //!< \return the Number of MemoryChunks needed to Manage "sMemorySize" Bytes. 95 std::size_t CalculateBestMemoryBlockSize(const std::size_t &sRequestedMemoryBlockSize) ; //!< return the amount of Memory which is best Managed by the MemoryChunks. 96 97 SMemoryChunk *FindChunkSuitableToHoldMemory(const std::size_t &sMemorySize) ; //!< \return a Chunk which can hold the requested amount of memory, or NULL, if none was found. 98 SMemoryChunk *FindChunkHoldingPointerTo(void *ptrMemoryBlock) ; //!< Find a Chunk which "Data"-Member is Pointing to the given "ptrMemoryBlock", or NULL if none was found. 99 100 SMemoryChunk *SkipChunks(SMemoryChunk *ptrStartChunk, unsigned int uiChunksToSkip) ; //!< Skip the given amount of Chunks, starting from the given ptrStartChunk. \return the Chunk at the "skipping"-Position. 101 SMemoryChunk *SetChunkDefaults(SMemoryChunk *ptrChunk) ; //!< Set "Default"-Values to the given Chunk 102 103 void FreeChunks(SMemoryChunk *ptrChunk) ; //!< Makes the memory linked to the given Chunk available in the MemoryPool again (by setting the "UsedSize"-Member to 0). 104 void DeallocateAllChunks() ; //!< Deallocates all Memory needed by the Chunks back to the Operating-System. 105 106 bool LinkChunksToData(SMemoryChunk *ptrNewChunk, unsigned int uiChunkCount, TByte *ptrNewMemBlock) ; //!< Link the given Memory-Block to the Linked-List of MemoryChunks... 107 void SetMemoryChunkValues(SMemoryChunk *ptrChunk, const std::size_t &sMemBlockSize) ; //!< Set the "UsedSize"-Member of the given "ptrChunk" to "sMemBlockSize". 108 bool RecalcChunkMemorySize(SMemoryChunk *ptrChunks, unsigned int uiChunkCount) ; //!< Recalcs the "DataSize"-Member of all Chunks whe the Memory-Pool grows (via "AllocateMemory()") 109 110 std::size_t MaxValue(const std::size_t &sValueA, const std::size_t &sValueB) const ; //!< \return the greatest of the two input values (A or B) 111 112 SMemoryChunk *m_ptrFirstChunk ; //!< Pointer to the first Chunk in the Linked-List of Memory Chunks 113 SMemoryChunk *m_ptrLastChunk ; //!< Pointer to the last Chunk in the Linked-List of Memory Chunks 114 SMemoryChunk *m_ptrCursorChunk ; //!< Cursor-Chunk. Used to speed up the navigation in the linked-List. 115 116 std::size_t m_sTotalMemoryPoolSize ; //!< Total Memory-Pool size in Bytes 117 std::size_t m_sUsedMemoryPoolSize ; //!< amount of used Memory in Bytes 118 std::size_t m_sFreeMemoryPoolSize ; //!< amount of free Memory in Bytes 119 120 std::size_t m_sMemoryChunkSize ; //!< amount of Memory which can be Managed by a single MemoryChunk. 121 unsigned int m_uiMemoryChunkCount ; //!< Total amount of "SMemoryChunk"-Objects in the Memory-Pool. 122 unsigned int m_uiObjectCount ; //!< Counter for "GetMemory()" / "FreeMemory()"-Operation. Counts (indirectly) the number of "Objects" inside the mem-Pool. 123 124 bool m_bSetMemoryData ; //!< Set to "true", if you want to set all (de)allocated Memory to a predefined Value (via "memset()"). Usefull for debugging. 125 std::size_t m_sMinimalMemorySizeToAllocate ; //!< The minimal amount of Memory which can be allocated via "AllocateMemory()". 126 } ; 127 128 } 129 130 #endif /* __INC_CMemoryPool_h__ */
CMemoryPool.cpp
1 /****************** 2 CMemoryPool.cpp 3 ******************/ 4 5 /*!\file CMemoryPool.cpp 6 * \brief CMemoryPool implementation. 7 */ 8 9 #include "../BasicIncludes.h" 10 #include "SMemoryChunk.h" 11 #include "CMemoryPool.h" 12 #include <string.h> 13 using namespace std; 14 15 namespace MemPool 16 { 17 18 static const int FREEED_MEMORY_CONTENT = 0xAA ; //!< Value for freed memory 19 static const int NEW_ALLOCATED_MEMORY_CONTENT = 0xFF ; //!< Initial Value for new allocated memory 20 21 /****************** 22 Constructor 23 ******************/ 24 CMemoryPool::CMemoryPool(const std::size_t &sInitialMemoryPoolSize, 25 const std::size_t &sMemoryChunkSize, 26 const std::size_t &sMinimalMemorySizeToAllocate, 27 bool bSetMemoryData) 28 { 29 m_ptrFirstChunk = NULL ; 30 m_ptrLastChunk = NULL ; 31 m_ptrCursorChunk = NULL ; 32 33 m_sTotalMemoryPoolSize = 0 ; 34 m_sUsedMemoryPoolSize = 0 ; 35 m_sFreeMemoryPoolSize = 0 ; 36 37 m_sMemoryChunkSize = sMemoryChunkSize ; 38 m_uiMemoryChunkCount = 0 ; 39 m_uiObjectCount = 0 ; 40 41 m_bSetMemoryData = bSetMemoryData ; 42 m_sMinimalMemorySizeToAllocate = sMinimalMemorySizeToAllocate ; 43 44 // Allocate the Initial amount of Memory from the Operating-System... 45 AllocateMemory(sInitialMemoryPoolSize) ; 46 } 47 48 /****************** 49 Destructor 50 ******************/ 51 CMemoryPool::~CMemoryPool() 52 { 53 FreeAllAllocatedMemory() ; 54 DeallocateAllChunks() ; 55 56 // Check for possible Memory-Leaks... 57 assert((m_uiObjectCount == 0) && "WARNING : Memory-Leak : You have not freed all allocated Memory") ; 58 } 59 60 /****************** 61 GetMemory 62 ******************/ 63 void *CMemoryPool::GetMemory(const std::size_t &sMemorySize) 64 { 65 std::size_t sBestMemBlockSize = CalculateBestMemoryBlockSize(sMemorySize) ; 66 SMemoryChunk *ptrChunk = NULL ; 67 while(!ptrChunk) 68 { 69 // Is a Chunks available to hold the requested amount of Memory ? 70 ptrChunk = FindChunkSuitableToHoldMemory(sBestMemBlockSize) ; 71 if(!ptrChunk) 72 { 73 // No chunk can be found 74 // => Memory-Pool is to small. We have to request 75 // more Memory from the Operating-System.... 76 sBestMemBlockSize = MaxValue(sBestMemBlockSize, CalculateBestMemoryBlockSize(m_sMinimalMemorySizeToAllocate)) ; 77 AllocateMemory(sBestMemBlockSize) ; 78 } 79 } 80 81 // Finally, a suitable Chunk was found. 82 // Adjust the Values of the internal "TotalSize"/"UsedSize" Members and 83 // the Values of the MemoryChunk itself. 84 m_sUsedMemoryPoolSize += sBestMemBlockSize ; 85 m_sFreeMemoryPoolSize -= sBestMemBlockSize ; 86 m_uiObjectCount++ ; 87 SetMemoryChunkValues(ptrChunk, sBestMemBlockSize) ; 88 89 // eventually, return the Pointer to the User 90 return ((void *) ptrChunk->Data) ; 91 } 92 93 /****************** 94 FreeMemory 95 ******************/ 96 void CMemoryPool::FreeMemory(void *ptrMemoryBlock, const std::size_t &sMemoryBlockSize) 97 { 98 // Search all Chunks for the one holding the "ptrMemoryBlock"-Pointer 99 // ("SMemoryChunk->Data == ptrMemoryBlock"). Eventually, free that Chunks, 100 // so it beecomes available to the Memory-Pool again... 101 SMemoryChunk *ptrChunk = FindChunkHoldingPointerTo(ptrMemoryBlock) ; 102 if(ptrChunk) 103 { 104 //std::cerr << "Freed Chunks OK (Used memPool Size : " << m_sUsedMemoryPoolSize << ")" << std::endl ; 105 FreeChunks(ptrChunk) ; 106 } 107 else 108 { 109 assert(false && "ERROR : Requested Pointer not in Memory Pool") ; 110 } 111 assert((m_uiObjectCount > 0) && "ERROR : Request to delete more Memory then allocated.") ; 112 m_uiObjectCount-- ; 113 } 114 115 /****************** 116 AllocateMemory 117 ******************/ 118 bool CMemoryPool::AllocateMemory(const std::size_t &sMemorySize) 119 { 120 // This function will allocate *at least* "sMemorySize"-Bytes from the Operating-System. 121 122 // How it works : 123 // Calculate the amount of "SMemoryChunks" needed to manage the requested MemorySize. 124 // Every MemoryChunk can manage only a certain amount of Memory 125 // (set by the "m_sMemoryChunkSize"-Member of the Memory-Pool). 126 // 127 // Also, calculate the "Best" Memory-Block size to allocate from the 128 // Operating-System, so that all allocated Memory can be assigned to a 129 // Memory Chunk. 130 // Example : 131 // You want to Allocate 120 Bytes, but every "SMemoryChunk" can only handle 132 // 50 Bytes ("m_sMemoryChunkSize = 50"). 133 // So, "CalculateNeededChunks()" will return the Number of Chunks needed to 134 // manage 120 Bytes. Since it is not possible to divide 120 Bytes in to 135 // 50 Byte Chunks, "CalculateNeededChunks()" returns 3. 136 // ==> 3 Chunks can Manage 150 Bytes of data (50 * 3 = 150), so 137 // the requested 120 Bytes will fit into this Block. 138 // "CalculateBestMemoryBlockSize()" will return the amount of memory needed 139 // to *perfectly* subdivide the allocated Memory into "m_sMemoryChunkSize" (= 50) Byte 140 // pieces. -> "CalculateBestMemoryBlockSize()" returns 150. 141 // So, 150 Bytes of memory are allocated from the Operating-System and 142 // subdivided into 3 Memory-Chunks (each holding a Pointer to 50 Bytes of the allocated memory). 143 // Since only 120 Bytes are requested, we have a Memory-Overhead of 144 // 150 - 120 = 30 Bytes. 145 // Note, that the Memory-overhead is not a bad thing, because we can use 146 // that memory later (it remains in the Memory-Pool). 147 // 148 149 unsigned int uiNeededChunks = CalculateNeededChunks(sMemorySize) ; 150 std::size_t sBestMemBlockSize = CalculateBestMemoryBlockSize(sMemorySize) ; 151 152 TByte *ptrNewMemBlock = (TByte *) malloc(sBestMemBlockSize) ; // allocate from Operating System 153 SMemoryChunk *ptrNewChunks = (SMemoryChunk *) malloc((uiNeededChunks * sizeof(SMemoryChunk))) ; // allocate Chunk-Array to Manage the Memory 154 assert(((ptrNewMemBlock) && (ptrNewChunks)) && "Error : System ran out of Memory") ; 155 156 // Adjust internal Values (Total/Free Memory, etc.) 157 m_sTotalMemoryPoolSize += sBestMemBlockSize ; 158 m_sFreeMemoryPoolSize += sBestMemBlockSize ; 159 m_uiMemoryChunkCount += uiNeededChunks ; 160 161 // Usefull for Debugging : Set the Memory-Content to a defined Value 162 if(m_bSetMemoryData) 163 { 164 memset(((void *) ptrNewMemBlock), NEW_ALLOCATED_MEMORY_CONTENT, sBestMemBlockSize) ; 165 } 166 167 // Associate the allocated Memory-Block with the Linked-List of MemoryChunks 168 return LinkChunksToData(ptrNewChunks, uiNeededChunks, ptrNewMemBlock) ; 169 } 170 171 /****************** 172 CalculateNeededChunks 173 ******************/ 174 unsigned int CMemoryPool::CalculateNeededChunks(const std::size_t &sMemorySize) 175 { 176 float f = (float) (((float)sMemorySize) / ((float)m_sMemoryChunkSize)) ; 177 return ((unsigned int) ceil(f)) ; 178 } 179 180 /****************** 181 CalculateBestMemoryBlockSize 182 ******************/ 183 std::size_t CMemoryPool::CalculateBestMemoryBlockSize(const std::size_t &sRequestedMemoryBlockSize) 184 { 185 unsigned int uiNeededChunks = CalculateNeededChunks(sRequestedMemoryBlockSize) ; 186 return std::size_t((uiNeededChunks * m_sMemoryChunkSize)) ; 187 } 188 189 /****************** 190 FreeChunks 191 ******************/ 192 void CMemoryPool::FreeChunks(SMemoryChunk *ptrChunk) 193 { 194 // Make the Used Memory of the given Chunk available 195 // to the Memory Pool again. 196 197 SMemoryChunk *ptrCurrentChunk = ptrChunk ; 198 unsigned int uiChunkCount = CalculateNeededChunks(ptrCurrentChunk->UsedSize); 199 for(unsigned int i = 0; i < uiChunkCount; i++) 200 { 201 if(ptrCurrentChunk) 202 { 203 // Step 1 : Set the allocated Memory to 'FREEED_MEMORY_CONTENT' 204 // Note : This is fully Optional, but usefull for debugging 205 if(m_bSetMemoryData) 206 { 207 memset(((void *) ptrCurrentChunk->Data), FREEED_MEMORY_CONTENT, m_sMemoryChunkSize) ; 208 } 209 210 // Step 2 : Set the Used-Size to Zero 211 ptrCurrentChunk->UsedSize = 0 ; 212 213 // Step 3 : Adjust Memory-Pool Values and goto next Chunk 214 m_sUsedMemoryPoolSize -= m_sMemoryChunkSize ; 215 ptrCurrentChunk = ptrCurrentChunk->Next ; 216 } 217 } 218 } 219 220 221 /****************** 222 FindChunkSuitableToHoldMemory 223 ******************/ 224 SMemoryChunk *CMemoryPool::FindChunkSuitableToHoldMemory(const std::size_t &sMemorySize) 225 { 226 // Find a Chunk to hold *at least* "sMemorySize" Bytes. 227 unsigned int uiChunksToSkip = 0 ; 228 bool bContinueSearch = true ; 229 SMemoryChunk *ptrChunk = m_ptrCursorChunk ; // Start search at Cursor-Pos. 230 for(unsigned int i = 0; i < m_uiMemoryChunkCount; i++) 231 { 232 if(ptrChunk) 233 { 234 if(ptrChunk == m_ptrLastChunk) // End of List reached : Start over from the beginning 235 { 236 ptrChunk = m_ptrFirstChunk ; 237 } 238 239 if(ptrChunk->DataSize >= sMemorySize) 240 { 241 if(ptrChunk->UsedSize == 0) 242 { 243 m_ptrCursorChunk = ptrChunk ; 244 return ptrChunk ; 245 } 246 } 247 uiChunksToSkip = CalculateNeededChunks(ptrChunk->UsedSize) ; 248 if(uiChunksToSkip == 0) uiChunksToSkip = 1 ; 249 ptrChunk = SkipChunks(ptrChunk, uiChunksToSkip) ; 250 } 251 else 252 { 253 bContinueSearch = false ; 254 } 255 } 256 return NULL ; 257 } 258 259 /****************** 260 SkipChunks 261 ******************/ 262 SMemoryChunk *CMemoryPool::SkipChunks(SMemoryChunk *ptrStartChunk, unsigned int uiChunksToSkip) 263 { 264 SMemoryChunk *ptrCurrentChunk = ptrStartChunk ; 265 for(unsigned int i = 0; i < uiChunksToSkip; i++) 266 { 267 if(ptrCurrentChunk) 268 { 269 ptrCurrentChunk = ptrCurrentChunk->Next ; 270 } 271 else 272 { 273 // Will occur, if you try to Skip more Chunks than actually available 274 // from your "ptrStartChunk" 275 assert(false && "Error : Chunk == NULL was not expected.") ; 276 break ; 277 } 278 } 279 return ptrCurrentChunk ; 280 } 281 282 /****************** 283 SetMemoryChunkValues 284 ******************/ 285 void CMemoryPool::SetMemoryChunkValues(SMemoryChunk *ptrChunk, const std::size_t &sMemBlockSize) 286 { 287 if((ptrChunk)) // && (ptrChunk != m_ptrLastChunk)) 288 { 289 ptrChunk->UsedSize = sMemBlockSize ; 290 } 291 else 292 { 293 assert(false && "Error : Invalid NULL-Pointer passed") ; 294 } 295 } 296 297 /****************** 298 WriteMemoryDumpToFile 299 ******************/ 300 bool CMemoryPool::WriteMemoryDumpToFile(const std::string &strFileName) 301 { 302 bool bWriteSuccesfull = false ; 303 std::ofstream ofOutputFile ; 304 ofOutputFile.open(strFileName.c_str(), std::ofstream::out | std::ofstream::binary) ; 305 306 SMemoryChunk *ptrCurrentChunk = m_ptrFirstChunk ; 307 while(ptrCurrentChunk) 308 { 309 if(ofOutputFile.good()) 310 { 311 ofOutputFile.write(((char *)ptrCurrentChunk->Data), ((std::streamsize) m_sMemoryChunkSize)) ; 312 bWriteSuccesfull = true ; 313 } 314 ptrCurrentChunk = ptrCurrentChunk->Next ; 315 } 316 ofOutputFile.close() ; 317 return bWriteSuccesfull ; 318 } 319 320 /****************** 321 LinkChunksToData 322 ******************/ 323 bool CMemoryPool::LinkChunksToData(SMemoryChunk *ptrNewChunks, unsigned int uiChunkCount, TByte *ptrNewMemBlock) 324 { 325 SMemoryChunk *ptrNewChunk = NULL ; 326 unsigned int uiMemOffSet = 0 ; 327 bool bAllocationChunkAssigned = false ; 328 for(unsigned int i = 0; i < uiChunkCount; i++) 329 { 330 if(!m_ptrFirstChunk) 331 { 332 m_ptrFirstChunk = SetChunkDefaults(&(ptrNewChunks[0])) ; 333 m_ptrLastChunk = m_ptrFirstChunk ; 334 m_ptrCursorChunk = m_ptrFirstChunk ; 335 } 336 else 337 { 338 ptrNewChunk = SetChunkDefaults(&(ptrNewChunks[i])) ; 339 m_ptrLastChunk->Next = ptrNewChunk ; 340 m_ptrLastChunk = ptrNewChunk ; 341 } 342 343 uiMemOffSet = (i * ((unsigned int) m_sMemoryChunkSize)) ; 344 m_ptrLastChunk->Data = &(ptrNewMemBlock[uiMemOffSet]) ; 345 346 // The first Chunk assigned to the new Memory-Block will be 347 // a "AllocationChunk". This means, this Chunks stores the 348 // "original" Pointer to the MemBlock and is responsible for 349 // "free()"ing the Memory later.... 350 if(!bAllocationChunkAssigned) 351 { 352 m_ptrLastChunk->IsAllocationChunk = true ; 353 bAllocationChunkAssigned = true ; 354 } 355 } 356 return RecalcChunkMemorySize(m_ptrFirstChunk, m_uiMemoryChunkCount) ; 357 } 358 359 /****************** 360 RecalcChunkMemorySize 361 ******************/ 362 bool CMemoryPool::RecalcChunkMemorySize(SMemoryChunk *ptrChunk, unsigned int uiChunkCount) 363 { 364 unsigned int uiMemOffSet = 0 ; 365 for(unsigned int i = 0; i < uiChunkCount; i++) 366 { 367 if(ptrChunk) 368 { 369 uiMemOffSet = (i * ((unsigned int) m_sMemoryChunkSize)) ; 370 ptrChunk->DataSize = (((unsigned int) m_sTotalMemoryPoolSize) - uiMemOffSet) ; 371 ptrChunk = ptrChunk->Next ; 372 } 373 else 374 { 375 assert(false && "Error : ptrChunk == NULL") ; 376 return false ; 377 } 378 } 379 return true ; 380 } 381 382 /****************** 383 SetChunkDefaults 384 ******************/ 385 SMemoryChunk *CMemoryPool::SetChunkDefaults(SMemoryChunk *ptrChunk) 386 { 387 if(ptrChunk) 388 { 389 ptrChunk->Data = NULL ; 390 ptrChunk->DataSize = 0 ; 391 ptrChunk->UsedSize = 0 ; 392 ptrChunk->IsAllocationChunk = false ; 393 ptrChunk->Next = NULL ; 394 } 395 return ptrChunk ; 396 } 397 398 /****************** 399 FindChunkHoldingPointerTo 400 ******************/ 401 SMemoryChunk *CMemoryPool::FindChunkHoldingPointerTo(void *ptrMemoryBlock) 402 { 403 SMemoryChunk *ptrTempChunk = m_ptrFirstChunk ; 404 while(ptrTempChunk) 405 { 406 if(ptrTempChunk->Data == ((TByte *) ptrMemoryBlock)) 407 { 408 break ; 409 } 410 ptrTempChunk = ptrTempChunk->Next ; 411 } 412 return ptrTempChunk ; 413 } 414 415 /****************** 416 FreeAllAllocatedMemory 417 ******************/ 418 void CMemoryPool::FreeAllAllocatedMemory() 419 { 420 SMemoryChunk *ptrChunk = m_ptrFirstChunk ; 421 while(ptrChunk) 422 { 423 if(ptrChunk->IsAllocationChunk) 424 { 425 free(((void *) (ptrChunk->Data))) ; 426 } 427 ptrChunk = ptrChunk->Next ; 428 } 429 } 430 431 /****************** 432 DeallocateAllChunks 433 ******************/ 434 void CMemoryPool::DeallocateAllChunks() 435 { 436 SMemoryChunk *ptrChunk = m_ptrFirstChunk ; 437 SMemoryChunk *ptrChunkToDelete = NULL ; 438 while(ptrChunk) 439 { 440 if(ptrChunk->IsAllocationChunk) 441 { 442 if(ptrChunkToDelete) 443 { 444 free(((void *) ptrChunkToDelete)) ; 445 } 446 ptrChunkToDelete = ptrChunk ; 447 } 448 ptrChunk = ptrChunk->Next ; 449 } 450 } 451 452 /****************** 453 IsValidPointer 454 ******************/ 455 bool CMemoryPool::IsValidPointer(void *ptrPointer) 456 { 457 SMemoryChunk *ptrChunk = m_ptrFirstChunk ; 458 while(ptrChunk) 459 { 460 if(ptrChunk->Data == ((TByte *) ptrPointer)) 461 { 462 return true ; 463 } 464 ptrChunk = ptrChunk->Next ; 465 } 466 return false ; 467 } 468 469 /****************** 470 MaxValue 471 ******************/ 472 std::size_t CMemoryPool::MaxValue(const std::size_t &sValueA, const std::size_t &sValueB) const 473 { 474 if(sValueA > sValueB) 475 { 476 return sValueA ; 477 } 478 return sValueB ; 479 } 480 481 }
main.cpp
1 /****************** 2 main.cpp 3 ******************/ 4 5 /*!\file main.cpp 6 * \brief Test-Program Main (Entry Point for the application). 7 */ 8 9 #include "BasicIncludes.h" 10 #include "MemPool/CMemoryPool.h" 11 #include <sys/time.h> 12 #include <iostream> 13 using namespace std; 14 15 16 MemPool::CMemoryPool *g_ptrMemPool = NULL ; //!< Global MemoryPool (Testing purpose) 17 unsigned int TestCount = 50000 ; //!< Nr of (de-)allocations (Testing purpose) 18 unsigned int ArraySize = 1000 ; //!< Size of the "Testing"-Array 19 20 long calculateUsedTime(const struct timeval &start, const struct timeval &end); 21 22 struct dd //alignment for four Bytes 23 { 24 char a; 25 char b; 26 double d; 27 short c; 28 }; 29 30 class myclass 31 { 32 public: 33 myclass() 34 { 35 printf("myclass sizeof(myclass)=%d\n", sizeof(myclass)); 36 } 37 virtual ~myclass(){} 38 39 private: 40 int a; 41 //int b; 42 }; 43 44 /*! \class MyTestClass_OPOverload 45 * \brief Test Class (Operator new/delete overloaded) 46 * 47 * The only purpose of this class is the testing of the Memory-Pool. 48 */ 49 class MyTestClass_OPOverload 50 { 51 public : 52 MyTestClass_OPOverload() 53 { 54 m_cMyArray[0] = 'H' ; 55 m_cMyArray[1] = 'e' ; 56 m_cMyArray[2] = 'l' ; 57 m_cMyArray[3] = 'l' ; 58 m_cMyArray[4] = 'o' ; 59 m_cMyArray[5] = NULL ; 60 m_strMyString = "This is a small Test-String" ; 61 m_iMyInt = 12345 ; 62 63 m_fFloatValue = 23456.7890f ; 64 m_fDoubleValue = 6789.012345 ; 65 66 Next = this ; 67 } 68 69 virtual ~MyTestClass_OPOverload() {} ; 70 71 void *operator new(std::size_t ObjectSize) 72 { 73 return g_ptrMemPool->GetMemory(ObjectSize) ; 74 } 75 76 void operator delete(void *ptrObject, std::size_t ObjectSize) 77 { 78 g_ptrMemPool->FreeMemory(ptrObject, ObjectSize) ; 79 } 80 private : 81 // Test-Data 82 char m_cMyArray[25] ; 83 unsigned char m_BigArray[10000] ; 84 std::string m_strMyString ; 85 int m_iMyInt ; 86 MyTestClass_OPOverload *Next ; 87 float m_fFloatValue ; 88 double m_fDoubleValue ; 89 } ; 90 91 /*! \class MyTestClass 92 * \brief Test Class ("Original" new/delete operator) 93 * 94 * The only purpose of this class is the testing of the Memory-Pool. 95 */ 96 class MyTestClass 97 { 98 public : 99 MyTestClass() 100 { 101 m_cMyArray[0] = 'H' ; 102 m_cMyArray[1] = 'e' ; 103 m_cMyArray[2] = 'l' ; 104 m_cMyArray[3] = 'l' ; 105 m_cMyArray[4] = 'o' ; 106 m_cMyArray[5] = NULL ; 107 m_strMyString = "This is a small Test-String" ; 108 m_iMyInt = 12345 ; 109 110 m_fFloatValue = 23456.7890f ; 111 m_fDoubleValue = 6789.012345 ; 112 113 Next = this ; 114 } 115 116 virtual ~MyTestClass() {} ; 117 private : 118 // Test-Data 119 char m_cMyArray[25] ; 120 unsigned char m_BigArray[10000] ; 121 std::string m_strMyString ; 122 int m_iMyInt ; 123 MyTestClass *Next ; 124 float m_fFloatValue ; 125 double m_fDoubleValue ; 126 } ; 127 128 /****************** 129 CreateGlobalMemPool 130 ******************/ 131 void CreateGlobalMemPool() 132 { 133 std::cerr << "Creating MemoryPool...." ; 134 g_ptrMemPool = new MemPool::CMemoryPool() ; 135 std::cerr << "OK" << std::endl ; 136 } 137 138 /****************** 139 DestroyGlobalMemPool 140 ******************/ 141 void DestroyGlobalMemPool() 142 { 143 std::cerr << "Deleting MemPool...." ; 144 if(g_ptrMemPool) ::delete g_ptrMemPool ; 145 std::cerr << "OK" << std::endl ; 146 } 147 148 /****************** 149 TestAllocationSpeedClassMemPool 150 ******************/ 151 void TestAllocationSpeedClassMemPool() 152 { 153 std::cerr << "Allocating Memory (Object Size MyTestClass_OPOverload : " << sizeof(MyTestClass_OPOverload) << ")..." ; 154 155 struct timeval start; 156 gettimeofday(&start, NULL); 157 for(unsigned int j = 0; j < TestCount; j++) 158 { 159 MyTestClass_OPOverload *ptrTestClass = new MyTestClass_OPOverload ; 160 delete ptrTestClass ; 161 } 162 163 struct timeval end; 164 gettimeofday(&end, NULL); 165 long usedtime = calculateUsedTime(start, end); 166 std::cerr << "OK" << std::endl ; 167 168 std::cerr << "Result for MemPool(Class Test) : " << (usedtime/1000) << " ms" << std::endl; 169 } 170 171 172 /****************** 173 TestAllocationSpeedClassHeap 174 ******************/ 175 void TestAllocationSpeedClassHeap() 176 { 177 std::cerr << "Allocating Memory (Object Size MyTestClass : " << sizeof(MyTestClass) << ")..." ; 178 struct timeval start; 179 gettimeofday(&start, NULL); 180 for(unsigned int j = 0; j < TestCount; j++) 181 { 182 MyTestClass *ptrTestClass = new MyTestClass ; 183 delete ptrTestClass ; 184 } 185 struct timeval end; 186 gettimeofday(&end, NULL); 187 long usedtime = calculateUsedTime(start, end); 188 189 std::cerr << "OK" << std::endl ; 190 std::cerr << "Result for Heap(Class Test) : " << usedtime/1000 << " ms" << std::endl ; 191 } 192 193 /****************** 194 TestAllocationSpeedArrayMemPool 195 ******************/ 196 void TestAllocationSpeedArrayMemPool() 197 { 198 std::cerr << "Allocating Memory (Object Size : " << ArraySize << ")..." ; 199 200 struct timeval start; 201 gettimeofday(&start, NULL); 202 for(unsigned int j = 0; j < TestCount; j++) 203 { 204 char *ptrArray = (char *) g_ptrMemPool->GetMemory(ArraySize) ; 205 g_ptrMemPool->FreeMemory(ptrArray, ArraySize) ; 206 } 207 208 struct timeval end; 209 gettimeofday(&end, NULL); 210 long usedtime = calculateUsedTime(start, end); 211 212 std::cerr << "OK" << std::endl ; 213 std::cerr << "Result for MemPool(Array-Test) : " << usedtime/1000 << " ms" << std::endl ; 214 } 215 216 /****************** 217 TestAllocationSpeedArrayHeap 218 ******************/ 219 void TestAllocationSpeedArrayHeap() 220 { 221 std::cerr << "Allocating Memory (Object Size : " << ArraySize << ")..." ; 222 223 struct timeval start; 224 gettimeofday(&start, NULL); 225 for(unsigned int j = 0; j < TestCount; j++) 226 { 227 char *ptrArray = (char *) malloc(ArraySize) ; 228 free(ptrArray) ; 229 } 230 231 struct timeval end; 232 gettimeofday(&end, NULL); 233 long usedtime = calculateUsedTime(start, end); 234 235 std::cerr << "OK" << std::endl ; 236 std::cerr << "Result for Heap(Array-Test) : " << usedtime/1000 << " ms" << std::endl ; 237 } 238 239 240 241 /****************** 242 WriteMemoryDumpToFile 243 ******************/ 244 void WriteMemoryDumpToFile() 245 { 246 std::cerr << "Writing MemoryDump to File..." ; 247 g_ptrMemPool->WriteMemoryDumpToFile("MemoryDump.bin") ; 248 std::cerr << "OK" << std::endl ; 249 } 250 251 long calculateUsedTime(const struct timeval &start, const struct timeval &end) 252 { 253 long usedtime_us = 0; 254 if((end.tv_usec - start.tv_usec) > 0 ) 255 usedtime_us = (end.tv_sec - start.tv_sec)*1000000 + end.tv_usec - start.tv_usec; 256 else 257 usedtime_us = (end.tv_sec - start.tv_sec -1)*1000000 + end.tv_usec + 1000000 - start.tv_usec; 258 return usedtime_us; 259 } 260 261 262 /****************** 263 main 264 ******************/ 265 int main(int argc, char *argv[]) 266 { 267 struct dd f={0}; 268 printf("sizeof(f)=%d\n", sizeof(f)); 269 printf("&f.a=0x%0x, &f.d=0x%0x, &f.c=0x%0x\n", &(f.a), &(f.d), &(f.c)); 270 271 myclass *aa = new myclass; 272 printf("sizeof(myclass)=%d\n", sizeof(myclass)); 273 274 printf("sizeof(float)=%d,sizeof(double)=%d, sizeof(int)=%d, sizeof(std::string)=%d\n", 275 sizeof(float), sizeof(double), sizeof(int), sizeof(std::string)); 276 277 std::cout << "MemoryPool Program started..." << std::endl ; 278 CreateGlobalMemPool() ; 279 280 TestAllocationSpeedArrayMemPool() ; 281 TestAllocationSpeedArrayHeap() ; 282 283 TestAllocationSpeedClassMemPool() ; 284 TestAllocationSpeedClassHeap() ; 285 286 WriteMemoryDumpToFile() ; 287 288 DestroyGlobalMemPool() ; 289 std::cout << "MemoryPool Program finished..." << std::endl ; 290 return 0 ; 291 }
Makefile
1 objects = main.o CMemoryPool.o 2 3 memorypool:$(objects) 4 g++ -o memorypool $(objects) 5 6 main.o: main.cpp BasicIncludes.h ./MemPool/CMemoryPool.h 7 g++ -c main.cpp 8 9 CMemoryPool.o:./MemPool/CMemoryPool.cpp ./MemPool/CMemoryPool.h 10 g++ -c ./MemPool/CMemoryPool.cpp 11 12 clean: 13 rm -f memorypool $(objects)