memory

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 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 #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; } 測試方法: // 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; }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章