本文说的对象分配器主要是针对一次分配多个对象的对象分配器。
设计上:
(1)单链表管理分配内存:以最大程度合适使用系统内存,减少系统内存碎片又能让系统找到合适的连续内存。
(2)分配多个对象的分配器跟单个对象的分配器的区别在于链表节点的成员里包含内存起始对象地址和末尾对象地址。
(3)根据单链表节点管理的内存起始对象地址和末尾对象地址来判断能否分配指定数量的对象(每次分配出来的指定数量的对象是连续内存的),如果找不到合适的内存就分配新的单链表节点及其管理的内存(每个单链表节点管理的内存分配最少是256个对象的长度)。
(4)需要另外使用个数组列表来保存所有的对象指针。本身不能回收对象指针。
(5)内存会在分配器析构时全都释放。
ps:分配单个对象的可参考:http://blog.csdn.net/chenjiayi_yun/article/details/24358135 。
/* 对象分配器,可一次分配多个 */ template <typename T> class CBaseObjAllocator { public: //内存块描述结构,用于查询内存块信息 struct DataBlockDesc { const char* lpBaseAddress;//内存块指针地址 size_t dwBlockSize; //内存块大小 }; private: //内存块链表节点 struct DataBlock { T* pFreePtr;//指向空闲的对象 T* pEndPtr;//指向对象内存块的结束 DataBlock* pPrev; }*m_pDataBlock; public: enum { AllocObjectCountOneTime = 1024 }; T* allocObject() { return allocObjects(1); } //申请属性指针 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); pBlock->pFreePtr = (T*)(pBlock + 1); pBlock->pEndPtr = pBlock->pFreePtr + nAllocCount; pBlock->pPrev = m_pDataBlock; m_pDataBlock = pBlock; } } //返回对象指针 result = pBlock->pFreePtr; pBlock->pFreePtr += nCount; 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; * CBaseObjAllocator<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; } CBaseObjAllocator() { m_pDataBlock = NULL; } ~CBaseObjAllocator() { DataBlock *pBlock, *pPrev; pBlock = m_pDataBlock; while (pBlock) { pPrev = pBlock->pPrev; free(pBlock); pBlock = pPrev; } m_pDataBlock = NULL; } };