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模型图:

MemoryPool UML schema

图中简要的描述了CMemoryPool class,更多的细节请查看源码中class声明。

 

那么,CMemoryPool如何实际工作?

 

关于 MemoryChunks

正如你在UML图中所看到的,内存池维护着一个SMemoryChunk链表,并管理着三个指向SMemoryChunk结构的指针(m_ptrFirstChunkm_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。MemoryPool after inital allocation

图中所示的为初始化分配后的内存池。
 
我们需要分配一组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链表将被成功的与原始内存块关联。

Memory and chunks linked togehter

最终,我们重新计算每一个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字节。

Memory-Segmentation finished

 

第三步:向内存池请求内存

现在,如果用户向内存池请求内存,那会发生什么呢?最开始,所有的SMemoryChunk在内存池中都是闲置可用状态:

All Memory available

让我们看看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字节:

Memory in use

如你所见,每一个SMemoryChunk管理100字节,所以,250字节并不是100的整数倍。这会引发什么情况呢?GetMemory将会返回指向第一个SMemoryChunk的指针,并设置其的UsedSize成员为300字节,因为300是100的整数倍数值中最小的,并且其大于250。多出的50字节称为"memory overhead".

FindChunkSuitableToHoldMemory寻找可用的SMemoryChunk时,它将只会从一个闲置的SMemoryChunk跳到另一个闲置的SMemoryChunk。这意味着,如果又有申请内存的请求达到,例子中的第四个SMemoryChunk将是寻找的起始点。

Jump to next valid chunk

 

如何使用代码

代码的使用简单而直接:

只需要在你的程序中包含"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) ;
}

Speed test Results for the array-test

 
//Class-Test for MemoryPool and Heap (重载了new与delete)
for(unsigned int j = 0; j < TestCount; j++)
{
    MyTestClass *ptrTestClass = new MyTestClass ;
    delete ptrTestClass ;
}

Speed test Results for the classes-test

 

关于代码

代码在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__ */
View Code

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__ */
View Code

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__ */
View Code

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__ */
View Code

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 }
View Code

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 }
View Code

 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)
View Code

 

posted on 2015-11-01 10:59  BlueSky~  阅读(694)  评论(0编辑  收藏  举报

导航