xiangyubobo的专栏

基本原理:一次申请多个对象的内存比多次申请一个对象的内存要快。内存池正式基于这个简单的道理。内存池先从系统中申请一块能容纳多个对象的内存块,以后每次申请一个对象都从内存池中获得;释放一个对象时内存归还内存池。

第一种是从《Effective C++》中看到的写法:

template<typename T>class object_pool{public:(size_t size);(void* p, size_t size);virtual ~object_pool(){};private:static void add_to_free_list(T *p);static void free_from_pool(T *p);protected:T *_next;private:static T *_next_free;static size_t _size;};template<typename T>T* object_pool<T>::_next_free = nullptr;template<typename T>size_t object_pool<T>::_size = 80;template<typename T>void object_pool<T>::add_to_free_list(T* p){p->_next = _next_free;_next_free = p;}template<typename T>void object_pool<T>::free_from_pool(T *p){}template<typename T>void object_pool<T>::operator delete(void *p, size_t size){if(p == nullptr){return ;}if(sizeof(T) != size){::operator delete(p);return ;}free_from_pool(static_cast<T*>(p));add_to_free_list(static_cast<T*>(p));}template<typename T>void* object_pool<T>::operator new(size_t size){if(sizeof(T) != size){return ::operator new(size);}if(_next_free == nullptr){T *new_block = static_cast<T*>(::operator new(sizeof(T)*_size));for(size_t i = 0; i < _size; ++i){add_to_free_list(&new_block[i]);}new_block[_size – 1]._next = nullptr;}T *res = _next_free;_next_free = res->_next;return res;}

这种内存池使用模板,能够适用于任何类。通过重载自身的静态operator new和operator delete操作,很自然的将对象内存分配过程接管到自己的代码中。使用MixIn方式继承,例如:

class Person:public object_pool<Person>{…};

使用非常方便,但是效率并不优秀,只比系统提供的new和delete操作快了大约10%。至于原因,我水平有限,只能猜测。大概是因为继承的关系,每次申请一个新对象需要调用父类的operator new,每次释放要给对象需要调用父类的operator delete。即使什么都不做,比常规new和delete操作慢上约16%。但这不像是效率不高的主要原因,还请各位高手指点。

第二种从一位大神博客里看到,这篇博客地址为:。下面是他博客中的代码(略有修改):

template<typename T>class CMemoryPool{public:EXPANSION_SIZE = 32;CMemoryPool(unsigned int nItemCount = EXPANSION_SIZE){ExpandFreeList(nItemCount);}~CMemoryPool(){CMemoryPool<T>* pNext = NULL;for(pNext = m_pFreeList; pNext != NULL; pNext = m_pFreeList){m_pFreeList = m_pFreeList->m_pFreeList;delete [](char*)pNext;}}void* Alloc(unsigned int){if(m_pFreeList == NULL){ExpandFreeList();}CMemoryPool<T>* pHead = m_pFreeList;m_pFreeList = m_pFreeList->m_pFreeList;return pHead;}void Free(void* p){CMemoryPool<T>* pHead = static_cast<CMemoryPool<T>*>(p);pHead->m_pFreeList = m_pFreeList;m_pFreeList = pHead;}protected:void ExpandFreeList(unsigned nItemCount = EXPANSION_SIZE){unsigned int nSize = sizeof(T) > sizeof(CMemoryPool<T>*) ? sizeof(T) : sizeof(CMemoryPool<T>*);CMemoryPool<T>* pLastItem = reinterpret_cast<CMemoryPool<T>*>(new char[nSize]);m_pFreeList = pLastItem;for(int i=0; i<nItemCount-1; ++i){pLastItem->m_pFreeList = reinterpret_cast<CMemoryPool<T>*>(new char[nSize]);pLastItem = pLastItem->m_pFreeList;}pLastItem->m_pFreeList = NULL;}private:CMemoryPool<T>* m_pFreeList;};

每次pool向系统申请固定数量(nItemCount)的内存单元,组织成空闲链表。虽然使用不及第一种方便,但是效率远比系统的new和delete高。 在ExpandFreeList函数中,第一句保证一个单元的空间能够容纳指针。其思想是:如果当前是空闲块,那么就用里面的空间保存指向下一个空闲单元的指针,可以节省空间;如果当前不是空闲块,那么事先已经把下一个空闲单元的指针保留给空闲链表头指针了,此时指针雨也没用了。所以是一种节约内存的写法。 使用例子:

class CTest{public:int m_n;int m_n1;void* operator new(size_t size){void* p = s_pool->Alloc(size);return p;}(void* p, size_t size){s_pool->Free(p);}static void NewPool(){s_pool = new CMemoryPool<CTest>;}static void DeletePool(){delete s_pool;s_pool = NULL;}static CMemoryPool<CTest>* s_pool;};CMemoryPool<CTest>* CTest::s_pool = NULL;如果寒暄只是打个招呼就了事的话,那与猴子的呼叫声有什么不同呢?事实上,

xiangyubobo的专栏

相关文章:

你感兴趣的文章:

标签云: