简明阐明C/C++内存分派的办理方案
副标题#e#
C/C++的内存分派(通过malloc或new)大概需要耗费许多时。
更糟糕的是,随 着时间的流逝,内存(memory)将形成碎片,所以一个应用措施的运行会越来越慢。当它 运行了很长时间和/或执行了许多的内存分派(释放)操纵的时候。出格是,你常常申请 很小的一块内存,堆(heap)会酿成碎片的。
办理方案:你本身的内存池一个( 大概的)办理要领是内存池(Memory Pool)。
在启动的时候,一个“内存 池”(Memory Pool)分派一块很大的内存,并将会将这个大块(block)分成较小 的块(smaller chunks)。每次你从内存池申请内存空间时,它会从先前已经分派的块( chunks)中获得,而不是从操纵系统。最大的优势在于:
1:很是少(几没有) 堆碎片
2: 比凡是的内存申请/释放(好比通过malloc, new等)的方法快别的, 你可以获得以下长处:1:查抄任何一个指针是否在内存池里2:写一个“堆转储 (Heap-Dump)”到你的硬盘(对过后的调试很是有用)
3: 某种“内 存泄漏检测(memory-leak detection)”:当你没有释放所有以前分派的内存时, 内存池(Memory Pool)会抛出一个断言(assertion)。
SMemoryChunk.h
#ifndef __SMEMORYCHUNK_H__
#define __SMEMORYCHUNK_H__
typedef unsigned char TByte ;
struct SMemoryChunk
{
TByte *Data; //数据
std::size_t DataSize; //该内存块的总巨细
std::size_t UsedSize; //实际利用的巨细
bool IsAllocationChunk;
SMemoryChunk *Next; //指向链表中下一个块的指针。
};
#endif
IMemoryBlock.h
#ifndef __IMEMORYBLOCK_H__
#define __IMEMORYBLOCK_H__
class IMemoryBlock
{
public :
virtual ~IMemoryBlock() {};
virtual void *GetMemory(const std::size_t &sMemorySize) = 0;
virtual void FreeMemory(void *ptrMemoryBlock, const std::size_t &sMemoryBlockSize) = 0;
};
#endif
#p#副标题#e#
CMemoryPool.h
#ifndef __CMEMORYPOOL_H__
#define __CMEMORYPOOL_H__
#include "IMemoryBlock.h"
#include "SMemoryChunk.h"
static const std::size_t DEFAULT_MEMORY_POOL_SIZE = 1000;//初始内存池的巨细
static const std::size_t DEFAULT_MEMORY_CHUNK_SIZE = 128;//Chunk的巨细
static const std::size_t DEFAULT_MEMORY_SIZE_TO_ALLOCATE = DEFAULT_MEMORY_CHUNK_SIZE * 2;
class CMemoryPool : public IMemoryBlock
{
public:
CMemoryPool(const std::size_t &sInitialMemoryPoolSize = DEFAULT_MEMORY_POOL_SIZE,
const std::size_t &sMemoryChunkSize = DEFAULT_MEMORY_CHUNK_SIZE,
const std::size_t &sMinimalMemorySizeToAllocate = DEFAULT_MEMORY_SIZE_TO_ALLOCATE,
bool bSetMemoryData = false
);
virtual ~CMemoryPool();
//从内 存池中申请内存
virtual void* GetMemory(const std::size_t &sMemorySize);
virtual void FreeMemory(void *ptrMemoryBlock, const std::size_t &sMemoryBlockSize);
private:
//申请 内存OS
bool AllocateMemory(const std::size_t &sMemorySize);
void FreeAllAllocatedMemory();
//计较可以分几多块
unsigned int CalculateNeededChunks(const std::size_t &sMemorySize);
//计较内存池最符合的巨细
std::size_t CMemoryPool::CalculateBestMemoryBlockSize(const std::size_t &sRequestedMemoryBlockSize);
//成立链表.每个结点Data指针指 向内存池中的内存地点
bool LinkChunksToData(SMemoryChunk* ptrNewChunks, unsigned int uiChunkCount, TByte* ptrNewMemBlock);
//从头计较块(Chunk)的巨细1024--896--768--640--512------------
bool RecalcChunkMemorySize(SMemoryChunk* ptrChunk, unsigned int uiChunkCount);
SMemoryChunk* SetChunkDefaults(SMemoryChunk *ptrChunk);
//搜索链表找到一个可以或许持有被申请巨细的内存块(Chunk).假如它返回NULL,那么在内 存池中没有可用的内存
SMemoryChunk* FindChunkSuitableToHoldMemory (const std::size_t &sMemorySize);
std::size_t MaxValue(const std::size_t &sValueA, const std::size_t &sValueB) const;
void SetMemoryChunkValues(SMemoryChunk *ptrChunk, const std::size_t &sMemBlockSize);
SMemoryChunk* SkipChunks(SMemoryChunk *ptrStartChunk, unsigned int uiChunksToSkip);
private:
SMemoryChunk *m_ptrFirstChunk;
SMemoryChunk *m_ptrLastChunk;
SMemoryChunk *m_ptrCursorChunk;
std::size_t m_sTotalMemoryPoolSize; //内存池的总巨细
std::size_t m_sUsedMemoryPoolSize; //以利用内存 的巨细
std::size_t m_sFreeMemoryPoolSize; //可用内存的巨细
std::size_t m_sMemoryChunkSize; //块(Chunk)的巨细
unsigned int m_uiMemoryChunkCount; //块(Chunk)的数量
unsigned int m_uiObjectCount;
bool m_bSetMemoryData ;
std::size_t m_sMinimalMemorySizeToAllocate;
};
#endif
CMemoryPool.h
#p#分页标题#e#
#include "stdafx.h"
#include "CMemorypool.h"
#include
#include
static const int NEW_ALLOCATED_MEMORY_CONTENT = 0xFF ;
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;
AllocateMemory(sInitialMemoryPoolSize);
}
CMemoryPool::~CMemoryPool ()
{
}
void* CMemoryPool::GetMemory(const std::size_t &sMemorySize)
{
std::size_t sBestMemBlockSize = CalculateBestMemoryBlockSize(sMemorySize);
SMemoryChunk* ptrChunk = NULL;
while(!ptrChunk)
{
ptrChunk = FindChunkSuitableToHoldMemory(sBestMemBlockSize);
//ptrChunk便是 NULL暗示内存池内存不足用
if(!ptrChunk)
{
sBestMemBlockSize = MaxValue(sBestMemBlockSize, CalculateBestMemoryBlockSize(m_sMinimalMemorySizeToAllocate));
//从OS申请更多的内存
AllocateMemory(sBestMemBlockSize);
}
}
//下面是找到可用的块(Chunk)代码
m_sUsedMemoryPoolSize += sBestMemBlockSize;
m_sFreeMemoryPoolSize -= sBestMemBlockSize;
m_uiObjectCount++;
//标志该块(Chunk)已用
SetMemoryChunkValues(ptrChunk, sBestMemBlockSize);
return ((void *) ptrChunk->Data);
}
void CMemoryPool::FreeMemory(void *ptrMemoryBlock, const std::size_t &sMemoryBlockSize)
{
}
bool CMemoryPool::AllocateMemory(const std::size_t &sMemorySize)
{
//计较可以分几多块(1000 / 128 = 8)
unsigned int uiNeededChunks = CalculateNeededChunks(sMemorySize);
//当内存池的初始 巨细为1000字节,块(Chunk)巨细128字节,分8块还差24字节.怎么办?
//办理 方案:多申请24字节
std::size_t sBestMemBlockSize = CalculateBestMemoryBlockSize(sMemorySize);
//向OS申请内存
TByte *ptrNewMemBlock = (TByte*) malloc(sBestMemBlockSize);
//分派一 个布局体SmemoryChunk的数组来打点内存块
SMemoryChunk *ptrNewChunks = (SMemoryChunk*) malloc((uiNeededChunks * sizeof(SMemoryChunk)));
m_sTotalMemoryPoolSize += sBestMemBlockSize;
m_sFreeMemoryPoolSize += sBestMemBlockSize;
m_uiMemoryChunkCount += uiNeededChunks;
if(m_bSetMemoryData)
{
memset(((void *) ptrNewMemBlock), NEW_ALLOCATED_MEMORY_CONTENT, sBestMemBlockSize);
}
return LinkChunksToData(ptrNewChunks, uiNeededChunks, ptrNewMemBlock);
}
unsigned int CMemoryPool::CalculateNeededChunks(const std::size_t &sMemorySize)
{
float f = (float) (((float)sMemorySize) / ((float)m_sMemoryChunkSize));
return ((unsigned int) ceil(f));
}
std::size_t CMemoryPool::CalculateBestMemoryBlockSize(const std::size_t &sRequestedMemoryBlockSize)
{
unsigned int uiNeededChunks = CalculateNeededChunks(sRequestedMemoryBlockSize);
return std::size_t((uiNeededChunks * m_sMemoryChunkSize));
}
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;
}
//按照块(Chunk)的巨细计较下一块的内存偏移地点
uiMemOffSet = (i * ((unsigned int) m_sMemoryChunkSize));
//结点 指向内存偏移地点
m_ptrLastChunk->Data = &(ptrNewMemBlock [uiMemOffSet]);
if(!bAllocationChunkAssigned)
{
m_ptrLastChunk->IsAllocationChunk = true;
bAllocationChunkAssigned = true;
}
}
return RecalcChunkMemorySize(m_ptrFirstChunk, m_uiMemoryChunkCount);
}
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;
}
SMemoryChunk* CMemoryPool::SetChunkDefaults(SMemoryChunk* ptrChunk)
{
if(ptrChunk)
{
ptrChunk->Data = NULL;
ptrChunk->DataSize = 0;
ptrChunk- >UsedSize = 0;
ptrChunk->IsAllocationChunk = false;
ptrChunk->Next = NULL;
}
return ptrChunk;
}
SMemoryChunk *CMemoryPool::FindChunkSuitableToHoldMemory(const std::size_t &sMemorySize)
{
unsigned int uiChunksToSkip = 0;
bool bContinueSearch = true;
SMemoryChunk *ptrChunk = m_ptrCursorChunk;
for(unsigned int i = 0; i < m_uiMemoryChunkCount; i++)
{
if(ptrChunk)
{
if(ptrChunk == m_ptrLastChunk)
{
ptrChunk = m_ptrFirstChunk;
}
if(ptrChunk->DataSize >= sMemorySize)
{
if(ptrChunk->UsedSize == 0)
{
m_ptrCursorChunk = ptrChunk;
return ptrChunk;
}
}
uiChunksToSkip = CalculateNeededChunks(ptrChunk->UsedSize);
if(uiChunksToSkip == 0) uiChunksToSkip = 1;
ptrChunk = SkipChunks(ptrChunk, uiChunksToSkip);
}
else
{
bContinueSearch = false
}
}
return NULL;
}
std::size_t CMemoryPool::MaxValue(const std::size_t &sValueA, const std::size_t &sValueB) const
{
if(sValueA > sValueB)
{
return sValueA;
}
return sValueB;
}
void CMemoryPool::SetMemoryChunkValues (SMemoryChunk *ptrChunk, const std::size_t &sMemBlockSize)
{
if((ptrChunk))
{
ptrChunk->UsedSize = sMemBlockSize;
}
else
{
assert(false && "Error : Invalid NULL-Pointer passed");
}
}
SMemoryChunk *CMemoryPool::SkipChunks(SMemoryChunk *ptrStartChunk, unsigned int uiChunksToSkip)
{
SMemoryChunk *ptrCurrentChunk = ptrStartChunk;
for(unsigned int i = 0; i < uiChunksToSkip; i++)
{
if(ptrCurrentChunk)
{
ptrCurrentChunk = ptrCurrentChunk->Next;
}
else
{
assert(false && "Error : Chunk == NULL was not expected.");
break ;
}
}
return ptrCurrentChunk;
}
测试要领:
#p#分页标题#e#
// 111.cpp : 界说节制台应用措施的进口点。
//
#include "stdafx.h"
#include "CMemoryPool.h"
CMemoryPool* g_pMemPool = NULL;
class testMemoryPool
{
public:
testMemoryPool(){
}
void *operator new(std::size_t ObjectSize)
{
return g_pMemPool->GetMemory (ObjectSize) ;
}
private:
char a[25];
bool b;
long c;
};//sizeof(32);
int _tmain(int argc, _TCHAR* argv[])
{
g_pMemPool = new CMemoryPool();
testMemoryPool* test = new testMemoryPool();
return 0;
}