自己做的一个固定大小对象内存池,效率大概为原始的new/delete的2倍
提升不高,不过好处是可以多次申请小对象,一次释放。(只适应于无动态申请资源的class)
vs2012测试情况如下:
// CHchFixLenMemPool.h #pragma once #ifndef __CHchFixLenMemPool_H__ #define __CHchFixLenMemPool_H__ #include <exception> #include <new> typedef struct __HchFixLenMemPoolLinkNode { __HchFixLenMemPoolLinkNode *m_next; }SHchFixLenMemPoolLinkNode; class CHchFixLenMemPool { public: CHchFixLenMemPool(size_t nFixLen, size_t nExpectObjectCnt = 0) { if ( nFixLen < (sizeof(void *) > sizeof(size_t) ? sizeof(void *) : sizeof(size_t)) ) { throw std::exception("nFixLen < max(sizeof(void *), sizeof(size_t))"); } //必须对齐,不然有可能出现内存访问异常 m_nFixLen = (nFixLen + sizeof(int) - 1) & ~(sizeof(int) - 1); m_nExpectObjectCnt = nExpectObjectCnt; if (m_nExpectObjectCnt < 1024) { m_nExpectObjectCnt = 1024; } m_allocSpaceLink = m_freeSpaceLink = NULL; allocFromSystem(); } ~CHchFixLenMemPool() { //遍历链表节点 while (m_allocSpaceLink) { SHchFixLenMemPoolLinkNode *pNext = m_allocSpaceLink->m_next; delete [](void *)m_allocSpaceLink; m_allocSpaceLink = pNext; } } void *alloc() { //如果存在已回收的空间,则直接分配出去 if (m_freeSpaceLink != NULL) { void *p = m_freeSpaceLink; m_freeSpaceLink = m_freeSpaceLink->m_next; return p; } //不然需要从m_allocSpaceLink里面切一块出来 char *pRetSpace = m_currAllocSpace; //pRetSpace指向待返回的空间 //如果上次new出来的内存还没分配完,则直接分配即可 if (m_nLeft != 0) { --m_nLeft; m_currAllocSpace += m_nFixLen; return pRetSpace; } //当前new出来的空间空间全部分配完 则需要重新向系统申请内存 allocFromSystem(); //这段跟前面分配逻辑是一样的 //考虑到cpu流水线预测,刻意这样重复写代码 pRetSpace = m_currAllocSpace; --m_nLeft; m_currAllocSpace += m_nFixLen; return pRetSpace; } void free(void *pSpace) { if (pSpace == NULL) { return; } //如果回收空间链表为空,则直接修改m_allocSpaceLinke即可 SHchFixLenMemPoolLinkNode *p = (SHchFixLenMemPoolLinkNode *)pSpace; if (m_allocSpaceLink == NULL) { m_allocSpaceLink = p; m_allocSpaceLink->m_next = NULL; return; } //否则将当前空间插到链表头 p->m_next = m_freeSpaceLink; m_freeSpaceLink = p; return; } private: //从系统分配内存 void allocFromSystem() { SHchFixLenMemPoolLinkNode *pNextLink = m_allocSpaceLink; //new失败会抛异常,不需要考虑 m_allocSpaceLink = (SHchFixLenMemPoolLinkNode *) new char[sizeof(SHchFixLenMemPoolLinkNode) + m_nFixLen * m_nExpectObjectCnt]; m_allocSpaceLink->m_next = pNextLink; m_nLeft = m_nExpectObjectCnt; m_currAllocSpace = ((char *)m_allocSpaceLink) + sizeof(SHchFixLenMemPoolLinkNode); } size_t m_nFixLen; //内存池定长 size_t m_nLeft; //已申请未分配个数 size_t m_nExpectObjectCnt; //每次申请多少个定长的空间 //当前可分配的空间指针 char *m_currAllocSpace; //回收空间链表 m_next指向下一个已回收空间 SHchFixLenMemPoolLinkNode *m_freeSpaceLink; //已向系统申请的空间链表 //链表中每个节点均指向new返回的指针 //m_next指向下一个已向申请空间 SHchFixLenMemPoolLinkNode *m_allocSpaceLink; }; template<typename T> T *newClassFromPool(CHchFixLenMemPool& objPool, const T& other) { T *pState = (T *)objPool.alloc(); new(pState) T(other); return pState; } template<typename T, typename T1> T *newClassFromPool(CHchFixLenMemPool& objPool, const T1& param) { T *pState = (T *)objPool.alloc(); new(pState) T(param); return pState; } template<typename T> T *newClassFromPool(CHchFixLenMemPool& objPool) { T *pState = (T *)objPool.alloc(); new(pState) T(); return pState; } template<class T> void deleteClassFromPool(CHchFixLenMemPool& objPool, T * pState) { pState->~T(); objPool.free(pState); } #ifdef __POP_NEW_FLAG__ #pragma pop_macro("new") #endif #endif
// testObjPool.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "CHchFixLenMemPool.h" #ifdef WIN32 #include <Windows.h> #endif #include <stdio.h> class CSimpleBuffer { public: CSimpleBuffer(size_t size = 32) { m_memSize = size; m_pMem = new char[m_memSize]; } CSimpleBuffer(const CSimpleBuffer& other) { m_memSize = other.m_memSize; m_pMem = new char[m_memSize]; memcpy(m_pMem, other.m_pMem, m_memSize); } char *getMem() { return m_pMem; } size_t getMemSize() { return m_memSize; } ~CSimpleBuffer() { delete []m_pMem; } private: size_t m_memSize; char *m_pMem; }; #ifdef WIN32 class CMyTiming { public: CMyTiming() { m_startFlag = false; } bool startTiming() //开始计时 { if (m_startFlag) { return false; } m_startFlag = true; QueryPerformanceFrequency(&m_litmp); /*获得时钟频率*/ m_dff = m_litmp.QuadPart; QueryPerformanceCounter(&m_litmp); /*获得初始值*/ m_qtBeg = m_litmp.QuadPart; return true; } double getTiming() //获得当前消耗时间 { if (!m_startFlag) { return -1; } QueryPerformanceCounter(&m_litmp); /*获得终止值*/ m_qtEnd = m_litmp.QuadPart; m_dfm = (m_qtEnd - m_qtBeg); m_dft = ((double) m_dfm) / m_dff; /*获得对应的时间值*/ return m_dft; } void endTiming() //停止计时 { m_startFlag = false; } private: bool m_startFlag; LARGE_INTEGER m_litmp; LONGLONG m_qtBeg, m_qtEnd, m_dff, m_dfm; double m_dft; }; #endif int _tmain(int argc, _TCHAR* argv[]) { const int nTimes = 209600; const int n = 8000; CSimpleBuffer *pArray[nTimes]; CMyTiming runTimeInfo; printf("total new times %d\n", nTimes * n); runTimeInfo.startTiming(); for (int i = 0; i < n * nTimes; i++) { int nPos = i / n; pArray[nPos] = new CSimpleBuffer(64); pArray[nPos]->getMem()[0] = '\0'; if (i % n != (n - 1)) delete pArray[nPos]; } for (int i = 0; i < nTimes; i++) { int nPos = i / n; strcpy(pArray[nPos]->getMem(), "hell8ffff fffff"); pArray[nPos]->getMem()[i % 64] = '2'; pArray[nPos]->getMem()[i % 32] = i; if (i % n == (n - 1)) delete pArray[nPos]; } printf("sec1 %.4f\n", runTimeInfo.getTiming()); runTimeInfo.endTiming(); runTimeInfo.startTiming(); CHchFixLenMemPool objPool(sizeof(CSimpleBuffer), 8096); for (int i = 0; i < n * nTimes; i++) { int nPos = i / n; pArray[nPos] = newClassFromPool<CSimpleBuffer, size_t>(objPool, 64); pArray[nPos]->getMem()[0] = '\0'; if (i % n != (n - 1)) deleteClassFromPool(objPool, pArray[nPos]); } for (int i = 0; i < nTimes; i++) { int nPos = i / n; strcpy(pArray[nPos]->getMem(), "hell8ffff fffff"); pArray[nPos]->getMem()[i % 64] = '2'; pArray[nPos]->getMem()[i % 32] = i; if (i % n == (n - 1)) deleteClassFromPool(objPool, pArray[nPos]); } printf("sec2 %.4f\n", runTimeInfo.getTiming()); return 0; }
~~积土成山,风雨兴焉;积水成渊,蛟龙生焉;~~~