一个内存池C++类的实现

一个内存池C++类的实现

在程序设计领域,程序员经常需要及时动态地产生出一些小型对象,例如读取解析文件时临时需要的缓冲区,动态创建视图时需要的视图对象,游戏程序中怪物,特效,场景物乃至于低级的链表节点等等。如果程序员只是天真地使用new和delete,在经过程序执行中不断反复的分配释放内存后,很快就会使原本完整连续的可用内存块变得支离破碎,这就是内存碎片即Memory Fragmentation问题。更糟的是内存碎片问题往往很难检测出来。

为了尽可能降低内存碎片的状况,并且得到高效的内存管理程序,除了从增加计算机配置,如增加内存条,和从程序的逻辑上着手,如减少读取解析文件时临时需要的缓冲区,减少动态创建视图的次数,减少游戏程序中怪物,特效,场景物出现频度之外,同时还需要从程序的低级层面,即从内存分配的功能面着手改善。

在用户每次new操作从系统索取内存空间时,C++的函数库除了配置所要求的内存块大小以外,还会另外生成一小块额外的内存块以记载相关的资料。对于经常进行产生与销毁的小型对象来说,这样的行为就显得十分浪费而不具效率。如果能够一次性的分配出一大块内存,然后再根据用户的需求传回部分内存块,这样就能改善new操作所产生的额外负担。

在这里,我参考早年微软MSJ期刊的一些资料写出了一个内存池C++类:CMemPool,这个内存池建立在树状的双向链表之上的,其相关结构体定义如下:

//树型内存块分配结构. typedef struct tagMEMORY_BLOCK MEMORY_BLOCK, *LPMEMORY_BLOCK; struct tagMEMORY_BLOCK { DWORD dwIndex; DWORD dwSize; LPMEMORY_BLOCK lpNext; LPMEMORY_BLOCK lpPrev; LPBYTE lpMemory; }; //内存池标头结构 typedef struct tagHEADER HEADER, *LPHEADER; struct tagHEADER { LPMEMORY_BLOCK lpHead; HANDLE hHeap; };

好了,我就不再啰嗦了,下面列出CMemPool类的源码,有不对之处,请不吝赐教!~~~

CMemPool类的头文件MemPool.h代码如下:

//==================================================================== // 内存池类CMemPool的头文件CMemPool.h //by 一剑(Loomman),QQ:28077188,MSN: [email protected] QQ裙:30515563 //==================================================================== #ifndef MEMPOOL_H #define MEMPOOL_H #define STRICT #define LEAN_AND_MEAN #include <windows.h> #include <assert.h> #include <stdio.h> #include <mbstring.h> //默认内存分配页大小设为8KB #define MEMPOOL_BLOCK_SIZE 8192 class CMemPool { public: CMemPool(); ~CMemPool(); BOOL Initialize(); VOID Destroy(); LPVOID GetAlignedMemory(DWORD dwSize, DWORD dwAlignSize); LPSTR GetDuplicateStringA(LPCSTR szSrc); LPWSTR GetDuplicateStringW(LPCWSTR szSrc); inline LPVOID GetMemory(DWORD dwSize) { return GetAlignedMemory(dwSize, 0); } inline TCHAR* GetStringBuffer(DWORD dwLen) { return (TCHAR*)GetAlignedMemory(dwLen * sizeof(TCHAR), 0); } inline LPSTR GetStringBufferA(DWORD dwLen) { return (LPSTR)GetAlignedMemory(dwLen * sizeof(CHAR), sizeof(CHAR)); } inline LPWSTR GetStringBufferW(DWORD dwLen) { return (LPWSTR)GetAlignedMemory(dwLen * sizeof(WCHAR), sizeof(WCHAR)); } inline DWORD* GetDwordBuffer() { return (DWORD*)GetAlignedMemory(sizeof(DWORD), 0); } private: BOOL AddMemory(DWORD dwSize); LPVOID handle; }; #endif //MEMPOOL_H

CMemPool类的实现文件MemPool.cpp代码如下:

//==================================================================== // 内存池类CMemPool的实现文件CMemPool.cpp //by 一剑(Loomman),QQ:28077188,MSN: [email protected] QQ裙:30515563 //==================================================================== #include "MemPool.h" //树型内存块分配结构. typedef struct tagMEMORY_BLOCK MEMORY_BLOCK, *LPMEMORY_BLOCK; struct tagMEMORY_BLOCK { DWORD dwIndex; DWORD dwSize; LPMEMORY_BLOCK lpNext; LPMEMORY_BLOCK lpPrev; LPBYTE lpMemory; }; //内存池标头结构 typedef struct tagHEADER HEADER, *LPHEADER; struct tagHEADER { LPMEMORY_BLOCK lpHead; HANDLE hHeap; }; //内存池对象构造函数 CMemPool::CMemPool() { handle = NULL; } //内存池对象析构函数 CMemPool::~CMemPool() { Destroy(); } //内存池对象初始化,首次分配8KB内存作为内存池 BOOL CMemPool::Initialize() { if( NULL == handle ) { HANDLE procHeap = GetProcessHeap(); // 分配内存池的头节点. handle = HeapAlloc(procHeap, 0, sizeof(HEADER)); if (handle) { LPHEADER header = (LPHEADER)handle; // 分配头节点成功,现在初始化内存池. header->lpHead = NULL; header->hHeap = procHeap; //初次实际分配8KB内存到内存池. BOOL ableToAddMemory = AddMemory(0); if (!ableToAddMemory) { //分配内存失败,系统资源瓶颈! HeapFree(header->hHeap, 0, handle); handle = NULL; } } } return (handle != NULL); } VOID CMemPool::Destroy() { if(handle != NULL) { LPMEMORY_BLOCK nextBlock; LPMEMORY_BLOCK blockToFree; LPHEADER poolHeader = (LPHEADER)handle; //遍历链表,进行释放内存操作. blockToFree = poolHeader->lpHead; while (blockToFree != NULL) { nextBlock = blockToFree->lpNext; HeapFree(poolHeader->hHeap, 0, blockToFree); blockToFree = nextBlock; } //别忘记了,内存池头结点也需要释放. HeapFree(poolHeader->hHeap, 0, handle); handle = NULL; } } LPVOID CMemPool::GetAlignedMemory(DWORD dwSize, DWORD dwAlignSize) { assert(handle != NULL); BOOL haveEnoughMemory = TRUE; LPVOID lpMemory = NULL; LPHEADER poolHeader = (LPHEADER)handle; LPMEMORY_BLOCK currentBlock; DWORD sizeNeeded; DWORD padLength; currentBlock = poolHeader->lpHead; // 判断是否需要更多的内存,如果是,则分配之. sizeNeeded = dwSize; if (currentBlock->dwSize - currentBlock->dwIndex < sizeNeeded + dwAlignSize) { haveEnoughMemory = AddMemory(sizeNeeded + dwAlignSize); currentBlock = poolHeader->lpHead; } // 现在有了足够的内存,返回它! if (haveEnoughMemory) { if (dwAlignSize) { padLength = (DWORD)currentBlock + sizeof(MEMORY_BLOCK) + currentBlock->dwIndex; currentBlock->dwIndex += (dwAlignSize - (padLength % dwAlignSize)) % dwAlignSize; } //这里得到了内存地址,返回它! lpMemory = (LPVOID)&(currentBlock->lpMemory[currentBlock->dwIndex]); currentBlock->dwIndex += sizeNeeded; } return lpMemory; } LPSTR CMemPool::GetDuplicateStringA(LPCSTR szSrc) { assert(szSrc); DWORD dwBytes = (_mbslen((const unsigned char*)szSrc) + 1) * sizeof(CHAR); LPSTR pString = (LPSTR)GetAlignedMemory(dwBytes, sizeof(CHAR)); if (pString) { _mbscpy_s((unsigned char*)pString, dwBytes, (const unsigned char*)szSrc); } return pString; } LPWSTR CMemPool::GetDuplicateStringW(LPCWSTR szSrc) { assert(szSrc); DWORD dwBytes = (wcslen(szSrc) + 1) * sizeof(WCHAR); LPWSTR pString = (LPWSTR)GetAlignedMemory(dwBytes, sizeof(WCHAR)); if (pString) { wcscpy_s(pString, dwBytes, szSrc); } return pString; } BOOL CMemPool::AddMemory(DWORD dwSize) { LPBYTE allocedMemory; LPMEMORY_BLOCK newBlock; LPHEADER poolHeader = (LPHEADER)handle; DWORD sizeNeeded; assert(poolHeader != NULL); // 计算需要分配内存的最小数量,并试图分配之. if (dwSize + sizeof(MEMORY_BLOCK) > MEMPOOL_BLOCK_SIZE) { sizeNeeded = dwSize + sizeof(MEMORY_BLOCK); } else { sizeNeeded = MEMPOOL_BLOCK_SIZE; } allocedMemory = (LPBYTE)HeapAlloc(poolHeader->hHeap, 0, sizeNeeded); if (allocedMemory) { // 使内存块的头部存储一个MEMORY_BLOCK结构. newBlock = (LPMEMORY_BLOCK)allocedMemory; newBlock->dwSize = sizeNeeded - sizeof(MEMORY_BLOCK); newBlock->lpMemory = allocedMemory + sizeof(MEMORY_BLOCK); newBlock->dwIndex = 0; // 把内存块链接到list中. if(poolHeader->lpHead) { poolHeader->lpHead->lpPrev = newBlock; } newBlock->lpNext = poolHeader->lpHead; newBlock->lpPrev = NULL; poolHeader->lpHead = newBlock; } // 如果allocedMemory 不是 NULL, 则表明我们成功了. return allocedMemory != NULL; }

CMemPool类使用演示程序代码如下:

#include <TCHAR.H> #include "MemPool.h" int main() { CMemPool mp; assert( mp.Initialize() ); for(int i = 0; i<100; i++) { TCHAR* psz = mp.GetStringBuffer(8192); _stprintf_s(psz, 8192, TEXT("now i=%d/n"), i); _tprintf(psz); } mp.Destroy(); return getchar(); }

 

在其中的_tprintf(psz);mp.Destroy();这两行打上断点,调试运行,观察windows任务管理器关于该进程的内存使用量呈明显的规律性增长。最后当执行完mp.Destroy();后该进程的内存使用量又恢复到未使用内存池时的状态。by Loomman, QQ:28077188, MSN: [email protected] QQ裙:30515563 ☆程序天堂☆ 请尊重作者原创,转载注明来自裂帛一剑博客,谢谢合作。

 

 

你可能感兴趣的:(C++,qq,struct,header,null,delete)