转自: http://blog.csdn.net/060/article/details/1326025
这是我翻译的文章,来自 Code Project,
原文作者: DanDanger2000 .
原文链接: http://www.codeproject.com/cpp/MemoryPool.asp
C++ 内存池
目录
l
引言
l
它怎样工作
l
示例
l
使用这些代码
l
好处
l
关于代码
l
ToDo
l
历史
引言
C/C++
的内存分配
(
通过
malloc
或
new
)
可能需要花费很多时。
更糟糕的是,随着时间的流逝,内存
(memory)
将形成碎片,所以一个应用程序的运行会越来越慢当它运行了很长时间和
/
或执行了很多的内存分配
(
释放
)
操作的时候。特别是,你经常申请很小的一块内存,堆
(heap)
会变成碎片的。
解决方案
:
你自己的内存池
一个
(
可能的
)
解决方法是内存池
(Memory Pool)
。
在启动的时候,一个
”
内存池
”(Memory Pool)
分配一块很大的内存,并将会将这个大块
(block)
分成较小的块
(smaller chunks)
。每次你从内存池申请内存空间时,它会从先前已经分配的块
(chunks)
中得到,
而不是从操作系统。最大的优势在于:
l
非常少
(
几没有
)
堆碎片
l
比通常的内存申请
/
释放
(
比如通过
malloc
,
new
等
)
的方式快
另外,你可以得到以下好处:
l
检查任何一个指针是否在内存池里
l
写一个
”
堆转储
(
Heap-Dump
)”
到你的硬盘
(
对事后的调试非常有用
)
l
某种
”
内存泄漏检测
(
memory-leak detection
)”
:当你没有释放所有以前分配的内存时,内存池
(Memory Pool)
会抛出一个
断言
(
assertion
).
它怎样工作
让我们看一看内存池
(Memory Pool)
的
UML
模式图:
这个模式图只显示了类
CMemoryPool
的一小部分,参看由
Doxygen
生成的文档以得到详细的类描述。
一个关于内存块
(MemoryChunks)
的单词
你应该从模式图中看到,
内存池
(Memory Pool)
管理了一个指向结构体
SMemoryChunk
(
m_ptrFirstChunk
,
m_ptrLastChunk
, and
m_ptrCursorChunk
)
的指针。这些块
(chunks)
建立一个内存块
(memory chunks)
的链表。各自指向链表中的下一个块
(chunk)
。当从操作系统分配到一块内存时,它将完全的被
SMemoryChunk
s
管理。让我们近一点看看一个块
(chunk)
。
typedef
struct
SMemoryChunk
{
TByte * Data ; // The actual Data
std::size_t DataSize ; // Size of the "Data"-Block
std::size_t UsedSize ; // actual used Size
bool IsAllocationChunk ; // true, when this MemoryChunks
// Points to a "Data"-Block
// which can be deallocated via "free()"
SMemoryChunk * Next ; // Pointer to the Next MemoryChunk
// in the List (may be NULL)
} SmemoryChunk;
{
TByte * Data ; // The actual Data
std::size_t DataSize ; // Size of the "Data"-Block
std::size_t UsedSize ; // actual used Size
bool IsAllocationChunk ; // true, when this MemoryChunks
// Points to a "Data"-Block
// which can be deallocated via "free()"
SMemoryChunk * Next ; // Pointer to the Next MemoryChunk
// in the List (may be NULL)
} SmemoryChunk;
每个块(chunk)持有一个指针,指针指向:
l
一小块内存
(
Data
)
,
l
从块
(chunk)
开始的可用内存的总大小
(
DataSize
)
,
l
实际使用的大小
(
UsedSize
)
,
l
以及一个指向链表中下一个块
(chunk)
的指针。
第一步:预申请内存
(pre-allocating the memory)
当你调用
CmemoryPool
的构造函数,内存池
(Memory Pool)
将从操作系统申请它的第一块
(
大的
)
内存块
(memory-chunk)
/*
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) ;
}
***************** */
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
最终完成了从操作系统申请内存。
/*
*****************
AllocateMemory
***************** */
bool CMemoryPool::AllocateMemory( const std::size_t & sMemorySize)
{
std::size_t sBestMemBlockSize = CalculateBestMemoryBlockSize(sMemorySize) ;
// allocate from Operating System
TByte * ptrNewMemBlock = (TByte * ) malloc (sBestMemBlockSize) ;
...
AllocateMemory
***************** */
bool CMemoryPool::AllocateMemory( const std::size_t & sMemorySize)
{
std::size_t sBestMemBlockSize = CalculateBestMemoryBlockSize(sMemorySize) ;
// allocate from Operating System
TByte * ptrNewMemBlock = (TByte * ) malloc (sBestMemBlockSize) ;
...
那么,是如何管理数据的呢?
第二步:已分配内存的分割
(segmentation of allocated memory)
正如前面提到的,
内存池(
Memory Pool
)
使用
SMemoryChunk
s
管理所有数据。从OS申请完内存之后,我们的块(chunks)和实际的内存块(block)之间就不存在联系:
Memory Pool after initial 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 " ) ;
...
...
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()
负责计算为管理已经得到的内存需要的块(chunks)的数量。分配完块(chunks)之后(通过
malloc
)
,
ptrNewChunks
将指向一个
SmemoryChunk
s
的数组。注意,数组里的块
(chunks)
现在持有的是垃圾数据,因为我们还没有给
chunk-members
赋有用的数据。内存池的堆
(Memory Pool-"Heap"):
Memory Pool after
SMemoryChunk
allocation
还是那句话,数据块
(data block)
和
chunks
之间没有联系。但是,
AllocateMemory()
会照顾它。
LinkChunksToData()
最后将把数据块
(data block)
和
chunks
联系起来,并将为每个
chunk-member
赋一个可用的值。
//
(AllocateMemory()continued) :
...
// Associate the allocated Memory-Block with the Linked-List of MemoryChunks
return LinkChunksToData(ptrNewChunks, uiNeededChunks, ptrNewMemBlock) ;
...
// 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]) ;
// The first Chunk assigned to the new Memory-Block will be
// a "AllocationChunk". This means, this Chunks stores the
// "original" Pointer to the MemBlock and is responsible for
// "free()"ing the Memory later....
if ( ! bAllocationChunkAssigned)
{
m_ptrLastChunk -> IsAllocationChunk = true ;
bAllocationChunkAssigned = true ;
}
}
return RecalcChunkMemorySize(m_ptrFirstChunk, m_uiMemoryChunkCount) ;
}
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]) ;
// The first Chunk assigned to the new Memory-Block will be
// a "AllocationChunk". This means, this Chunks stores the
// "original" Pointer to the MemBlock and is responsible for
// "free()"ing the Memory later....
if ( ! bAllocationChunkAssigned)
{
m_ptrLastChunk -> IsAllocationChunk = true ;
bAllocationChunkAssigned = true ;
}
}
return RecalcChunkMemorySize(m_ptrFirstChunk, m_uiMemoryChunkCount) ;
}
让我们一步步地仔细看看这个重要的函数:第一行检查链表里是否已经有可用的块(chunks):
...
if ( ! m_ptrFirstChunk)
...
if ( ! m_ptrFirstChunk)
...
我们第一次给类的成员赋值:
...
m_ptrFirstChunk = SetChunkDefaults( & (ptrNewChunks[ 0 ])) ;
m_ptrLastChunk = m_ptrFirstChunk ;
m_ptrCursorChunk = m_ptrFirstChunk ;
...
m_ptrFirstChunk = SetChunkDefaults( & (ptrNewChunks[ 0 ])) ;
m_ptrLastChunk = m_ptrFirstChunk ;
m_ptrCursorChunk = m_ptrFirstChunk ;
...
m_ptrFirstChunk
现在指向块数组(
chunks-array
)
的
第一个
块,每一个块严格的管理来自内存(
memory block
)
的
m_sMemoryChunkSize
个字节。一个
”
偏移量
”(offset)
——这个值是可以计算的所以每个
(chunk)
能够指向内存块
(
memory block)
的特定部分。
uiMemOffSet
=
(i
*
((unsigned
int
) m_sMemoryChunkSize)) ;
m_ptrLastChunk -> Data = & (ptrNewMemBlock[uiMemOffSet]) ;
m_ptrLastChunk -> Data = & (ptrNewMemBlock[uiMemOffSet]) ;
另外,每个新的来自数组的
SmemoryChunk
将被追加到链表的最后
一个
元素(并且它自己将成为最后一个元素):
...
m_ptrLastChunk -> Next = ptrNewChunk ;
m_ptrLastChunk = ptrNewChunk ;
...
m_ptrLastChunk -> Next = ptrNewChunk ;
m_ptrLastChunk = ptrNewChunk ;
...
在接下来的
"
for
loop
"
中,内存池
(memory pool)
将连续的给数组中的所有块
(chunks)
赋一个可用的数据。
Memory and chunks linked together, pointing to valid data
最后,我们必须重新计算每个块(chunk)能够管理的总的内存大小。这是一个费时的,但是在新的内存追加到内存池时必须做的一件事。这个总的大小将被赋值给chunk的
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
***************** */
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
之后,每个chunk都知道它指向的空闲内存的大小。所以,将很容易确定一个chunk是否能够持有一块特定大小的内存:当
DataSize
成员大于
(
或等于
)
已经申请的内存大小以及
DataSize
成员是
0
,于是
chunk
有能力持有一块内存。最后,内存分割完成了。为了不让事情太抽象,我们假定内存池
(memory pool )
包含600字节,每个chunk持有100字节。
Memory segmentation finished. Each chunk manages exactly 100 bytes
第三步:从内存池申请内存
(requesting memory from the memory pool)
那么,如果用户从内存池申请内存会发生什么?最初,内存池里的所有数据是空闲的可用的:
All memory blocks are available
我们看看
GetMemory
:
/*
*****************
GetMemory
***************** */
void * CMemoryPool::GetMemory( const std::size_t & sMemorySize)
{
std::size_t sBestMemBlockSize = CalculateBestMemoryBlockSize(sMemorySize) ;
SMemoryChunk * ptrChunk = NULL ;
while ( ! ptrChunk)
{
// Is a Chunks available to hold the requested amount of Memory ?
ptrChunk = FindChunkSuitableToHoldMemory(sBestMemBlockSize) ;
if ( ! ptrChunk)
{
// No chunk can be found
// => Memory-Pool is to small. We have to request
// more Memory from the Operating-System....
sBestMemBlockSize = MaxValue(sBestMemBlockSize,
CalculateBestMemoryBlockSize(m_sMinimalMemorySizeToAllocate)) ;
AllocateMemory(sBestMemBlockSize) ;
}
}
// Finally, a suitable Chunk was found.
// Adjust the Values of the internal "TotalSize"/"UsedSize" Members and
// the Values of the MemoryChunk itself.
m_sUsedMemoryPoolSize += sBestMemBlockSize ;
m_sFreeMemoryPoolSize -= sBestMemBlockSize ;
m_uiObjectCount ++ ;
SetMemoryChunkValues(ptrChunk, sBestMemBlockSize) ;
// eventually, return the Pointer to the User
return (( void * ) ptrChunk -> Data) ;
}
GetMemory
***************** */
void * CMemoryPool::GetMemory( const std::size_t & sMemorySize)
{
std::size_t sBestMemBlockSize = CalculateBestMemoryBlockSize(sMemorySize) ;
SMemoryChunk * ptrChunk = NULL ;
while ( ! ptrChunk)
{
// Is a Chunks available to hold the requested amount of Memory ?
ptrChunk = FindChunkSuitableToHoldMemory(sBestMemBlockSize) ;
if ( ! ptrChunk)
{
// No chunk can be found
// => Memory-Pool is to small. We have to request
// more Memory from the Operating-System....
sBestMemBlockSize = MaxValue(sBestMemBlockSize,
CalculateBestMemoryBlockSize(m_sMinimalMemorySizeToAllocate)) ;
AllocateMemory(sBestMemBlockSize) ;
}
}
// Finally, a suitable Chunk was found.
// Adjust the Values of the internal "TotalSize"/"UsedSize" Members and
// the Values of the MemoryChunk itself.
m_sUsedMemoryPoolSize += sBestMemBlockSize ;
m_sFreeMemoryPoolSize -= sBestMemBlockSize ;
m_uiObjectCount ++ ;
SetMemoryChunkValues(ptrChunk, sBestMemBlockSize) ;
// eventually, return the Pointer to the User
return (( void * ) ptrChunk -> Data) ;
}
当用户从内存池中申请内存是,它将从链表搜索一个能够持有被申请大小的chunk。那意味着:
l
那个chunk的
DataSize
必须大于或等于被申请的内存的大小;
l
那个chunk的
UsedSize
必须是
0
。
这由
FindChunkSuitableToHoldMemory
方法完成。如果它返回
NULL
,那么在内存池中没有可用的内存。这将导致
AllocateMemory
的调用
(
上面讨论过
)
,它将从
OS
申请更多的内存。如果返回值不是
NULL
,
一个可用的
chunk
被发现。
SetMemoryChunkValues
会调整
chunk
成员的值,并且最后
Data
指针被返回给用户
...
/*
*****************
SetMemoryChunkValues
***************** */
void CMemoryPool::SetMemoryChunkValues(SMemoryChunk * ptrChunk,
const std::size_t & sMemBlockSize)
{
if (ptrChunk)
{
ptrChunk -> UsedSize = sMemBlockSize ;
}
...
}
SetMemoryChunkValues
***************** */
void CMemoryPool::SetMemoryChunkValues(SMemoryChunk * ptrChunk,
const std::size_t & sMemBlockSize)
{
if (ptrChunk)
{
ptrChunk -> UsedSize = sMemBlockSize ;
}
...
}
示例
假设,用户从内存池申请
250
字节:
Memory in use
如我们所见,每个内存块(chunk)管理100字节,所以在这里250字节不是很合适。发生了什么事?Well,
GetMemory
从第一个chunk返回
Data
指针并把它的
UsedSize
设为300字节,因为300字节是能够被管理的内存的最小值并大于等于250。那些剩下的
(300 - 250 = 50)
字节被称为内存池的
"
memory overhead
"
。这没有看起来的那么坏,因为这些内存还可以使用
(
它仍然在内存池里
)
。
当
FindChunkSuitableToHoldMemory
搜索可用
chunk
时,它仅仅从一个空的
chunk
跳到另一个空的
chunk
。那意味着,如果某个人申请另一块内存
(memory-chunk)
,第四块
(
持有
300
字节的那个
)
会成为下一个可用的
("valid") chunk
。
Jump to next valid chunk
使用代码
使用这些代码是简单的、直截了当的:只需要在你的应用里包含
"
CMemoryPool.h
"
,并添加几个相关的文件到你的
IDE/Makefile:
- CMemoryPool.h
- CMemoryPool.cpp
- IMemoryBlock.h
- SMemoryChunk.h
你只要创建一个
CmemoryPool
类的实例,你就可以从它里面申请内存。所有的内存池的配置在
CmemoryPool
类的构造函数
(
使用可选的参数
)
里完成。看一看头文件
("
CMemoryPool.h
")
或
Doxygen-doku
。所有的文件都有详细的
(Doxygen-)
文档。
应用举例
MemPool::CMemoryPool
*
g_ptrMemPool
=
new
MemPool::CMemoryPool() ;
char * ptrCharArray = ( char * ) g_ptrMemPool -> GetMemory( 100 ) ;
...
g_ptrMemPool -> FreeMemory(ptrCharArray, 100 ) ;
delete g_ptrMemPool ;
char * ptrCharArray = ( char * ) g_ptrMemPool -> GetMemory( 100 ) ;
...
g_ptrMemPool -> FreeMemory(ptrCharArray, 100 ) ;
delete g_ptrMemPool ;
好处
内存转储
(Memory dump)
你可以在任何时候通过
WriteMemoryDumpToFile(
strFileName
)
写一个
"memory dump"
到你的
HDD
。看看一个简单的测试类的构造函数
(
使用内存池重载了
new
和
delete
运算符
)
:
/*
*****************
Constructor
***************** */
MyTestClass::MyTestClass()
{
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 ;
}
Constructor
***************** */
MyTestClass::MyTestClass()
{
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 " ) ;
g_ptrMemPool -> WriteMemoryDumpToFile( " MemoryDump.bin " ) ;
看一看内存转储文件
("
MemoryDump.bin
"):
如你所见,在内存转储里有
MyTestClass
类的所有成员的值。明显的,
"Hello"
字符串
(
m_cMyArray
)
在那里,以及整型数
m_iMyInt
(3930 0000 = 0x3039 = 12345 decimal)
等等。这对调式很有用。
速度测试
我在
Windows
平台上做了几个非常简单的测试
(
通过
timeGetTime()
)
,但是结果说明内存池大大提高了应用程序的速度。所有的测试在
Microsoft Visual Studio .NET 2003
的
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) ;
}
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) ;
}
Results for the "array-test
//Class-Test for MemoryPool and Heap (overloaded new/delete)
//
Class-Test for MemoryPool and Heap (overloaded new/delete)
for (unsigned int j = 0 ; j < TestCount; j ++ )
{
MyTestClass * ptrTestClass = new MyTestClass ;
delete ptrTestClass ;
}
for (unsigned int j = 0 ; j < TestCount; j ++ )
{
MyTestClass * ptrTestClass = new MyTestClass ;
delete ptrTestClass ;
}
Results for the "classes-test" (overloaded
new
/
delete
operators)
关于代码
这些代码在Windows和Linux平台的下列编译器测试通过:
- Microsoft Visual C++ 6.0
- Microsoft Visual C++ .NET 2003
- MinGW (GCC) 3.4.4 (Windows)
- GCC 4.0.X (Debian GNU Linux)
Microsoft Visual C++ 6.0
(
*.dsw
,
*.dsp
)
和
Microsoft Visual C++ .NET 2003
(
*.sln
,
*.vcproj
)
的工程文件已经包含在下载中。内存池仅用于
ANSI/ISO C++,
所以它应当在任何
OS
上的标准的
C++
编译器编译。在
64
位处理器上应当没有问题。
注意
:内存池不是线程安全的。
这个内存池还有许多改进的地方
;-) ToDo
列表包括:
l
对于大量的内存,
memory-"overhead"
能够足够大。
l
某些
CalculateNeededChunks
调用能够通过从新设计某些方法而去掉
l
更多的稳定性测试
(
特别是对于那些长期运行的应用程序
)
l
做到线程安全。