178 lines
4.9 KiB
C++
178 lines
4.9 KiB
C++
|
|
#pragma once
|
|||
|
|
|
|||
|
|
/***********************************************************************
|
|||
|
|
对象内存申请器
|
|||
|
|
|
|||
|
|
仅适用于大量的小内存对象的申请优化,且对象是长时间使用而不需释放的场合★
|
|||
|
|
★!此内存管理器不是多线程安全的!★
|
|||
|
|
|
|||
|
|
用于对连续的相同对象的小块内存申请进行优化。申请器只提供申请对象的功能并且能够将内存
|
|||
|
|
申请的效率进行最大化提升,不提供释放对象所占用内存的功能。所有对象所占用的内存将在申请
|
|||
|
|
器销毁时才被释放。
|
|||
|
|
|
|||
|
|
************************************************************************/
|
|||
|
|
#include "ObjectAllocStat.hpp"
|
|||
|
|
#include "Platform.h"
|
|||
|
|
|
|||
|
|
template <typename T>
|
|||
|
|
class CObjectAllocator : public CObjectAllocatorStat
|
|||
|
|
{
|
|||
|
|
public:
|
|||
|
|
//#ifdef _ENABLE_OBJ_COUNT_STATICS_
|
|||
|
|
typedef CObjectAllocatorStat Inherited;
|
|||
|
|
//#endif
|
|||
|
|
|
|||
|
|
//内存块描述结构,用于查询内存块信息
|
|||
|
|
struct DataBlockDesc
|
|||
|
|
{
|
|||
|
|
const char* lpBaseAddress;//内存块指针地址
|
|||
|
|
size_t dwBlockSize; //内存块大小
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
//内存块链表节点
|
|||
|
|
struct DataBlock
|
|||
|
|
{
|
|||
|
|
T* pFreePtr; //指向空闲的对象
|
|||
|
|
T* pEndPtr; //指向对象内存块的结束
|
|||
|
|
DataBlock* pPrev;
|
|||
|
|
} *m_pDataBlock;
|
|||
|
|
|
|||
|
|
public:
|
|||
|
|
enum {
|
|||
|
|
AllocObjectCountOneTime = 1024
|
|||
|
|
};
|
|||
|
|
//申请属性指针
|
|||
|
|
T* allocObjects(const INT_PTR nCount = 1)
|
|||
|
|
{
|
|||
|
|
T* result;
|
|||
|
|
DataBlock *pBlock = m_pDataBlock;
|
|||
|
|
//尝试从当前内存块中申请nCount的对象,如果内存块中没有足够的对象,则向之前的内存块中查找是否具有足够的空闲对象
|
|||
|
|
if ( !pBlock || pBlock->pEndPtr - pBlock->pFreePtr < nCount )
|
|||
|
|
{
|
|||
|
|
//向之前的内存块中查找是否具有足够的空闲对象
|
|||
|
|
while (pBlock && (pBlock = pBlock->pPrev))
|
|||
|
|
{
|
|||
|
|
if ( pBlock->pEndPtr - pBlock->pFreePtr >= nCount )
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
//如果所有内存块中都没有足够的对象则申请新内存块
|
|||
|
|
if ( pBlock == NULL )
|
|||
|
|
{
|
|||
|
|
INT_PTR nAllocCount = __max(nCount, AllocObjectCountOneTime);
|
|||
|
|
pBlock = (DataBlock*)malloc(sizeof(DataBlock) + sizeof(T) * nAllocCount);
|
|||
|
|
memset(pBlock, 0, sizeof(DataBlock) + sizeof(T) * nAllocCount);
|
|||
|
|
//#ifdef _ENABLE_OBJ_COUNT_STATICS_
|
|||
|
|
m_nAllocObjNum += nAllocCount;
|
|||
|
|
//#endif
|
|||
|
|
pBlock->pFreePtr = (T*)(pBlock + 1);
|
|||
|
|
pBlock->pEndPtr = pBlock->pFreePtr + nAllocCount;
|
|||
|
|
pBlock->pPrev = m_pDataBlock;
|
|||
|
|
m_pDataBlock = pBlock;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
//返回对象指针
|
|||
|
|
result = pBlock->pFreePtr;
|
|||
|
|
pBlock->pFreePtr += nCount;
|
|||
|
|
//#ifdef _ENABLE_OBJ_COUNT_STATICS_
|
|||
|
|
m_nUsedObjNum += nCount;
|
|||
|
|
//#endif
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
//获取内存块数量
|
|||
|
|
inline INT_PTR blockCount() const
|
|||
|
|
{
|
|||
|
|
INT_PTR result = 0;
|
|||
|
|
DataBlock *pBlock = m_pDataBlock;
|
|||
|
|
|
|||
|
|
while (pBlock)
|
|||
|
|
{
|
|||
|
|
result++;
|
|||
|
|
pBlock = pBlock->pPrev;
|
|||
|
|
}
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
/*
|
|||
|
|
* Comments: 枚举内存块描述信息
|
|||
|
|
* Param LPCVOID lpEnumKey: 上次枚举的返回值,作为枚举下一个的依据,第一次枚举此值必须为NULL。
|
|||
|
|
* Param DataBlockDesc & desc: 用于保存内存块描述的对象
|
|||
|
|
* @Return LPCVOID: 返回一个内存块枚举key指针,便于进行下次枚举。如果返回值为NULL则表示枚举结束
|
|||
|
|
*
|
|||
|
|
* ★★注意★★:枚举内存块描述的操作是倒叙进行的,第一个被枚举的内存块描述为左后一个内存块的描述!
|
|||
|
|
*
|
|||
|
|
* ★★示例代码★★:-------------------------------------------------
|
|||
|
|
* LPCVOID lpEnumKey = NULL;
|
|||
|
|
* CObjectAllocator<T>::DataBlockDesc desc;
|
|||
|
|
* while (lpEnumKey = allocator.enumBlockDesc(lpEnumKey, desc))
|
|||
|
|
* {
|
|||
|
|
* printf("Memory Block Info { Address = %X, Size = %u }",
|
|||
|
|
* desc.lpBaseAddress, desc.dwBlockSize);
|
|||
|
|
* }
|
|||
|
|
* --------------------------------------------------------------
|
|||
|
|
*/
|
|||
|
|
inline LPCVOID enumBlockDesc(LPCVOID lpEnumKey, DataBlockDesc &desc) const
|
|||
|
|
{
|
|||
|
|
DataBlock *pBlock = (DataBlock*)lpEnumKey;
|
|||
|
|
if (!pBlock)
|
|||
|
|
pBlock = m_pDataBlock;
|
|||
|
|
else pBlock = pBlock->pPrev;
|
|||
|
|
|
|||
|
|
if (pBlock)
|
|||
|
|
{
|
|||
|
|
desc.lpBaseAddress = ((const char*)pBlock) + sizeof(*pBlock);
|
|||
|
|
desc.dwBlockSize = pBlock->pEndPtr - desc.lpBaseAddress;
|
|||
|
|
return pBlock;
|
|||
|
|
}
|
|||
|
|
return NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//#ifdef _ENABLE_OBJ_COUNT_STATICS_
|
|||
|
|
CObjectAllocator(LPCTSTR lpszDesc = NULL) : Inherited(sizeof(T), CObjectAllocatorStat::enAT_ObjectAlloc, lpszDesc)
|
|||
|
|
{
|
|||
|
|
m_pDataBlock = NULL;
|
|||
|
|
}
|
|||
|
|
/*
|
|||
|
|
#else
|
|||
|
|
|
|||
|
|
CObjectAllocator(LPCTSTR lpszDesc = NULL)
|
|||
|
|
{
|
|||
|
|
m_pDataBlock = NULL;
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
~CObjectAllocator()
|
|||
|
|
{
|
|||
|
|
DataBlock *pBlock, *pPrev;
|
|||
|
|
pBlock = m_pDataBlock;
|
|||
|
|
while (pBlock)
|
|||
|
|
{
|
|||
|
|
pPrev = pBlock->pPrev;
|
|||
|
|
free(pBlock);
|
|||
|
|
pBlock = pPrev;
|
|||
|
|
}
|
|||
|
|
m_pDataBlock = NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
inline CObjectAllocator& operator = (const CObjectAllocator &rhs)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
//#ifdef _ENABLE_OBJ_COUNT_STATICS_
|
|||
|
|
Inherited::operator=(rhs);
|
|||
|
|
//#endif
|
|||
|
|
m_pDataBlock = rhs.m_pDataBlock;
|
|||
|
|
//#ifdef _ENABLE_OBJ_COUNT_STATICS_
|
|||
|
|
|
|||
|
|
((CObjectAllocatorStat*)(&rhs))->removeFromStat();
|
|||
|
|
Inherited::addToStat();
|
|||
|
|
//#endif
|
|||
|
|
return *this;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
CObjectAllocator(const CObjectAllocator &rhs);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
|
|||
|
|
|