http://blog.csdn.net/neustar1/article/details/7478311
利用C/C++开发大型应用程序中,内存的管理与分配是一个需要认真考虑的部分。
本文描述了内存池设计原理并给出内存池的实现代码,代码支持Windows和Linux,多线程安全。
内存池设计过程中需要考虑好内存的分配与释放问题,其实也就是空间和时间的矛盾。
有的内存池设计得很巧妙,内存分配与需求相当,但是会浪费过多的时间去查找分配与释放,这就得不偿失;
实际使用中,我们更多的是关心内存分配的速度,而不是内存的使用效率。基于此,本文按照如下思想设计实现内存池。
主要包含三个结构:StiaticMemory, MemoryChunk和MemoryBlock,三者之间的关系如下图所示:
1.内存的分配:
(1)如果分配大小超过1024,直接采用malloc分配,分配的时候多分配sizeof(size_t)字节,用于保存该块的大小;
(2)否则根据分配大小,查找到容纳该大小的最小size的MemoryChunk;
(3)查找MemoryChunk的链表指针pList,找到空闲的MemoryBlock返回;
(4)如果pList为NULL,临时创建MemoryBlock返回;
(5)MemoryBlock头部包含两个成员,pChunk指向的所属的MemoryChunk对象,size表明大小,其后才是给用户使用的空间;
2.内存的释放:
(1)根据释放的指针,查找器size头部,即减去sizeof(size_t)字节,判断该块的大小;
(2)如果大小超过1024,直接free;
(3)否则交给MemoryChunk处理,而块的头部保存了该指针,因此直接利用该指针就可以收回该内存。
注意的问题:
上述设计的内存池通过冗余的头部来实现内存块的分配与释放,减少了内存池的操作时间,速度上要优于原始的malloc和free操作,同时减少了内存碎片的增加。
但是该设计中没有去验证释放的块冗余头部的正确性,因此故意释放不属于内存池中的块或者修改头部信息都会导致内存池操作失败,当然这些可以由程序员来控制。
此外,内存池中分配出去的内存块如果不主动释放,内存池没有保留信息,不会自动释放,但是在退出的时候会验证验证是否完全释放,其实这个在系统测试时候就可以检测出来,我想这个缺陷也是可以弥补的,在此提出,希望使用者注意。
下面贴上源码,如果对代码有任何建议或者发现存在的Bug,希望与我联系,共同学习交流,Tx。
MemoryChunk.h 文件,线程安全
- #ifndef MEMORY_CHUNK_H
- #define MEMORY_CHUNK_H
- #include <cstdio>
- #include <cassert>
- #include <cstdlib>
- #ifdef WIN32
- #include <windows.h>
- typedef CRITICAL_SECTION MUTEXTYPE;
- #define INITMUTEX(hMutex) InitializeCriticalSection(&hMutex)
- #define DELMUTEX(hMutex) DeleteCriticalSection(&hMutex)
- #define LOCK(hMutex) EnterCriticalSection(&hMutex)
- #define UNLOCK(hMutex) LeaveCriticalSection(&hMutex)
- #else
- #include <pthread.h>
- typedef pthread_mutex_t MUTEXTYPE;
- #define INITMUTEX(hMutex) pthread_mutex_init(&hMutex,NULL)
- #define DELMUTEX(hMutex) pthread_mutex_destroy(&hMutex)
- #define LOCK(hMutex) pthread_mutex_lock(&hMutex)
- #define UNLOCK(hMutex) pthread_mutex_unlock(&hMutex)
- #endif
- class MemoryChunk;
- /** @struct MemoryBlock
- *
- */
- struct BlockHeader
- {
- MemoryChunk* pChunk;
- size_t len;
- };
- struct MemoryBlock;
- struct BlockData
- {
- union{
- MemoryBlock* pNext;
- char pBuffer;
- };
- };
- struct MemoryBlock
- {
- BlockHeader header;
- BlockData data;
- };
- /** @class MemoryChunk
- *
- */
- class MemoryChunk
- {
- public:
- MemoryChunk(size_t size, int count)
- {
- INITMUTEX(hMutex);
- this->pFreeList=NULL;
- this->size=size;
- this->count=0;
- MemoryBlock* pBlock;
- while(count--){
- pBlock=CreateBlock();
- if(!pBlock)break;
- pBlock->data.pNext=pFreeList;
- pFreeList=pBlock;
- }
- }
- ~MemoryChunk()
- {
- int tempcount=0;
- MemoryBlock* pBlock;
- while(pBlock=pFreeList){
- pFreeList=pBlock->data.pNext;
- DeleteBlock(pBlock);
- ++tempcount;
- }
- assert(tempcount==count);//!确保释放完全
- DELMUTEX(hMutex);
- }
- void* malloc()
- {
- MemoryBlock* pBlock;
- LOCK(hMutex);
- if(pFreeList){
- pBlock=pFreeList;
- pFreeList=pBlock->data.pNext;
- }
- else{
- if(!(pBlock=CreateBlock())){
- UNLOCK(hMutex);
- return NULL;
- }
- }
- UNLOCK(hMutex);
- return &pBlock->data.pBuffer;
- }
- static void free(void* pMem)
- {
- MemoryBlock* pBlock=(MemoryBlock*)((char*)pMem-sizeof(BlockHeader));
- pBlock->header.pChunk->free(pBlock);
- }
- void free(MemoryBlock* pBlock)
- {
- LOCK(hMutex);
- pBlock->data.pNext=pFreeList;
- pFreeList=pBlock;
- UNLOCK(hMutex);
- }
- MemoryChunk* Next(){return pNext;}
- protected:
- MemoryBlock* CreateBlock()
- {
- MemoryBlock* pBlock=(MemoryBlock*)::malloc(sizeof(BlockHeader)+size);
- if(pBlock){
- pBlock->header.pChunk=this;
- pBlock->header.len=size;
- ++count;
- }
- return pBlock;
- }
- void DeleteBlock(MemoryBlock* pBlock)
- {
- ::free(pBlock);
- }
- private:
- MemoryBlock* pFreeList;
- size_t size;//!Block大小
- int count;//!Block数目
- MemoryChunk* pNext;
- MUTEXTYPE hMutex;
- };
- #endif
StaticMemory.h文件,内存池对象
- #ifndef STATIC_MEMORY_H
- #define STATIC_MEMORY_H
- #include "MemoryChunk.h"
- /** @ StaticMemory.h
- * 定义实现内存池
- * 采用固定大小策略进行内存管理与分配
- * 减少因大量小内存分配导致的内存碎片增加
- */
- struct HeapHeader
- {
- size_t size;
- };
- struct MemoryHeap
- {
- HeapHeader header;
- char pBuffer;
- };
- class StaticMemory
- {
- public:
- typedef enum{MAX_SIZE=1024,MIN_SIZE=sizeof(MemoryChunk*)};
- StaticMemory()
- {
- chunkcount=0;
- for(size_t size=MIN_SIZE; size<=MAX_SIZE; size*=2)++chunkcount;
- //pChunkList=(MemoryChunk**)malloc(sizeof(MemoryChunk*)*chunkcount);
- pChunkList=new MemoryChunk*[chunkcount];
- int index=0;
- for(size_t size=MIN_SIZE; size<=MAX_SIZE; size*=2)
- {
- pChunkList[index++]=new MemoryChunk(size,1000);
- }
- }
- ~StaticMemory()
- {
- for(int index=0; index<chunkcount; ++index)
- {
- delete pChunkList[index];
- }
- //free(pChunkList);
- delete[] pChunkList;
- }
- void* Malloc(size_t size)
- {
- if(size>MAX_SIZE){
- return malloc(size);
- }
- int index=0;
- for(size_t tsize=MIN_SIZE; tsize<=MAX_SIZE; tsize*=2){
- if(tsize>=size)break;
- ++index;
- }
- return pChunkList[index]->malloc();
- }
- void Free(void* pMem)
- {
- if(!free(pMem))MemoryChunk::free(pMem);
- }
- protected:
- void* malloc(size_t size)
- {
- MemoryHeap* pHeap=(MemoryHeap*)::malloc(sizeof(HeapHeader)+size);
- if(pHeap){
- pHeap->header.size=size;
- return &pHeap->pBuffer;
- }
- return NULL;
- }
- bool free(void* pMem)
- {
- MemoryHeap* pHeap=(MemoryHeap*)((char*)pMem-sizeof(HeapHeader));
- if(pHeap->header.size>MAX_SIZE){
- ::free(pHeap);
- return true;
- }
- return false;
- }
- private:
- MemoryChunk** pChunkList;
- int chunkcount;
- };
- #endif
ObejctManager.h文件,用于实现对象的创建与管理,比较简易。
- #ifndef OBJECT_MANAGER_H
- #define OBJECT_MANAGER_H
- #include "StaticMemory.h"
- /** @class ObjectManager
- * 实现利用内存池创建对象
- * 要求对象具有缺省构造函数
- */
- template<typename T>
- class ObjectManager
- {
- public:
- typedef T ObjectType;
- static ObjectType* Create(StaticMemory* pool)
- {
- void* pobject=pool->Malloc(sizeof(T));
- new(pobject) ObjectType();
- return static_cast<ObjectType*>(pobject);
- }
- static void Delete(StaticMemory* pool, ObjectType* pobject)
- {
- pobject->~ObjectType();
- pool->Free(pobject);
- }
- };
- #endif
测试结果:
分单线程和多线程进行测试,重复的内存分配与释放在实际使用中是不太可能的,为了模拟实际使用,通过随机数来确定分配内存大小,同时也通过随机数来确定分配与释放操作。在测试过程中限制最大分配大小为1024,目的是为了测试小内存块的分配情况对比。
分配与释放次数 | malloc/free | 内存池 |
---|---|---|
100,000 | 0.01s | 0.01s |
1,000,000 | 0.15s | 0.11s |
10,000,000 | 1.26s | 0.60s |
100,000,000 | 9.21s | 5.99s |
1,000,000,000 | 92.70s | 61.46s |
线程数目 | malloc/free | 内存池 |
1/1,000,000 | 0.15s | 0.10s |
2/1,000,000 | 1.49s | 0.73s |
4/1,000,000 | 9.945s | 6.71s |
8/1,000,000 | 45.60s | 28.82s |
进行多线程测试主要是测试多线程运行下,加锁给内存分配带来的影响,因此为了排除CPU的影响,测试采用的机器为16盒,16G内存的Linux服务器。
具体配置如下:
Intel(R) Xeon(R) CPU E5630 @ 2.53GHz
stepping : 2
cpu MHz : 2527.084
cache size : 12288 KB
http://www.cppblog.com/weiym/archive/2013/04/08/199238.html
总结下常见的C++内存池,以备以后查询。
应该说没有一个内存池适合所有的情况, 根据不同的需求选择正确的内存池才是正道.
(1)最简单的固定大小缓冲池
适用于频繁分配和释放固定大小对象的情况, 关于这个内存池,我这里总结过:一个高效的内存池实现
(2)dlmalloc
应该来说相当优秀的内存池, 支持大对象和小对象,并且已被广泛使用。到这里下载:ftp://g.oswego.edu/pub/misc/malloc.c
关于dlmalloc的内部原理和使用资料可以参考:内存分配器dlmalloc 2.8.3源码浅析.doc
(3) SGI STL 中的内存分配器( allocator )
SGI STL 的 allocator 应该是目前设计最优秀的 C++ 内存分配器之一了,它的运作原理候捷老师在《 STL 源码剖析》里讲解得非常清楚。基本思路是设计一个 free_list[16] 数组,负责管理从 8 bytes 到 128 bytes 不同大小的内存块( chunk ),每一个内存块都由连续的固定大小( fixed size block )的很多 chunk 组成,并用指针链表串接起来。比如说
free_list[3]->start_notuse->next_notuse->next_notuse->...->end_notuse;
当用户要获取此大小的内存时,就在 free_list 的链表找一个最近的 free chunk 回传给用户,同时将此 chunk 从 free_list 里删除,即把此 chunk 前后 chunk 指针链结起来。用户使用完释放的时候,则把此chunk 放回到 free_list 中,应该是放到最前面的 start_free 的位置。这样经过若干次 allocator 和 deallocator 后, free_list 中的链表可能并不像初始的时候那么是 chunk 按内存分布位置依次链接的。假如free_list 中不够时, allocator 会自动再分配一块新的较大的内存区块来加入到 free_list 链表中。
可以自动管理多种不同大小内存块并可以自动增长的内存池,这是 SGI STL 分配器设计的特点。
(4) Loki 中的小对象分配器( small object allocator )
Loki 的分配器与 SGI STL 的原理类似,不同之处是它管理 free_list 不是固定大小的数组,而是用一个 vector 来实现,因此可以用户指定 fixed size block 的大小,不像 SGI STL 是固定最大 128 bytes 的。另外它管理 free chunks 的方式也不太一样, Loki 是由一列记录了 free block 位置等信息的 Chunk 类的链表来维护的, free blocks 则是分布在另外一个连续的大内存区间中。而且 free Chunks 也可以根据使用情况自动增长和减少合适的数目,避免内存分配得过多或者过少。
(5) Boost 的 object_pool
Boost 中的 object_pool 也是一个可以根据用户具体应用类的大小来分配内存块的,也是通过维护一个 free nodes 的链表来管理的。可以自动增加 nodes 块,初始是 32 个 nodes ,每次增加都以两倍数向 system heap 要内存块。 object_pool 管理的内存块需要在其对象销毁的时候才返还给 system heap 。
(6)ACE 中的 ACE_Cached_Allocator 和 ACE_Free_List
ACE 框架中也有一个可以维护固定大小的内存块的分配器,原理与上面讲的内存池都差不多。它是通过在 ACE_Cached_Allocator 中定义个 Free_list 链表来管理一个连续的大内存块的,里面包含很多小的固定大小的未使用的区块( free chunk ),同时还使用 ACE_unbounded_Set 维护一个已使用的 chuncks ,管理方式与上面讲的内存池类似。也可以指定 chunks 的数目,也可以自动增长,定义大致如下所示:
class ACE_Cached_Allocator : public ACE_New_Allocator<T> {
public:
// Create a cached memory pool with @a n_chunks chunks
// each with sizeof (TYPE) size.
ACE_Cached_Allocator(SIZET n_chunks = ACE_DEFAULT_INIT_CHUNKS);
T* allocate();
void deallocate(T* p);
private:
// List of memory that we have allocated.
Fast_Unbounded_Set<char *> _allocated_chunks;
// Maintain a cached memory free list.
ACE_Cached_Free_List<ACE_Cached_Mem_Pool_Node<T> > _free_list;
};
Google的开源项目gperftools, 主页在这里:https://code.google.com/p/gperftools/,该内存池也被大家广泛好评,并且在google的各种开源项目中被使用, 比如webkit就用到了它。
http://blog.chinaunix.net/uid-479984-id-2114952.html
http://blog.csdn.net/060/archive/2006/10/08/1326025.aspx
原文作者: DanDanger2000.
原文链接: http://www.codeproject.com/cpp/MemoryPool.asp
C++ 内存池
malloc
, new等)的方式快CMemoryPool
的一小部分,参看由
Doxygen生成的文档以得到详细的类描述。SMemoryChunk
(m_ptrFirstChunk
, m_ptrLastChunk
, and m_ptrCursorChunk
)的指针。这些块(chunks)建立一个内存块(memory chunks)的链表。各自指向链表中的下一个块(chunk)。当从操作系统分配到一块内存时,它将完全的被SMemoryChunk
s管理。让我们近一点看看一个块(chunk)。
{
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;
Data
),DataSize
),UsedSize
),CmemoryPool
的构造函数,内存池(Memory Pool)将从操作系统申请它的第一块(大的)内存块(memory-chunk)******************/
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) ;
...
SMemoryChunk
s管理所有数据。从OS申请完内存之后,我们的块(chunks)和实际的内存块(block)之间就不存在联系:SmemoryChunk
的数组来管理内存块:...
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"):SMemoryChunk
allocationAllocateMemory()
会照顾它。LinkChunksToData()
最后将把数据块(data block)和chunks联系起来,并将为每个chunk-member赋一个可用的值。...
// 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) ;
}
if(!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)的特定部分。m_ptrLastChunk->Data = &(ptrNewMemBlock[uiMemOffSet]) ;
SmemoryChunk
将被追加到链表的最后一个元素(并且它自己将成为最后一个元素):m_ptrLastChunk->Next = ptrNewChunk ;
m_ptrLastChunk = ptrNewChunk ;
...
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
之后,每个chunk都知道它指向的空闲内存的大小。所以,将很容易确定一个chunk是否能够持有一块特定大小的内存:当DataSize
成员大于(或等于)已经申请的内存大小以及DataSize
成员是0,于是chunk有能力持有一块内存。最后,内存分割完成了。为了不让事情太抽象,我们假定内存池(memory pool )包含600字节,每个chunk持有100字节。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) ;
}
DataSize
必须大于或等于被申请的内存的大小; 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 ;
}
...
}
GetMemory
从第一个chunk返回 Data
指针并把它的UsedSize
设为300字节,因为300字节是能够被管理的内存的最小值并大于等于250。那些剩下的(300 - 250 = 50)字节被称为内存池的"memory overhead"。这没有看起来的那么坏,因为这些内存还可以使用(它仍然在内存池里)。FindChunkSuitableToHoldMemory
搜索可用chunk时,它仅仅从一个空的chunk跳到另一个空的chunk。那意味着,如果某个人申请另一块内存(memory-chunk),第四块(持有300字节的那个)会成为下一个可用的("valid") chunk。- CMemoryPool.h
- CMemoryPool.cpp
- IMemoryBlock.h
- SMemoryChunk.h
CmemoryPool
类的实例,你就可以从它里面申请内存。所有的内存池的配置在CmemoryPool
类的构造函数(使用可选的参数)里完成。看一看头文件("CMemoryPool.h")或Doxygen-doku。所有的文件都有详细的(Doxygen-)文档。char *ptrCharArray = (char *) g_ptrMemPool->GetMemory(100) ;
...
g_ptrMemPool->FreeMemory(ptrCharArray, 100) ;
delete g_ptrMemPool ;
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 ;
}
g_ptrMemPool->WriteMemoryDumpToFile("MemoryDump.bin") ;
MyTestClass
类的所有成员的值。明显的,"Hello"字符串(m_cMyArray
)在那里,以及整型数m_iMyInt
(3930 0000 = 0x3039 = 12345 decimal)等等。这对调式很有用。timeGetTime()
),但是结果说明内存池大大提高了应用程序的速度。所有的测试在Microsoft Visual Studio .NET 2003的debug模式下(测试计算机: Intel Pentium IV Processor (32 bit), 1GB RAM, MS Windows XP Professional).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++)
{
MyTestClass *ptrTestClass = new MyTestClass ;
delete ptrTestClass ;
}
- Microsoft Visual C++ 6.0
- Microsoft Visual C++ .NET 2003
- MinGW (GCC) 3.4.4 (Windows)
- GCC 4.0.X (Debian GNU Linux)
CalculateNeededChunks
调用能够通过从新设计某些方法而去掉来源:https://www.cnblogs.com/virusolf/p/4482315.html