天天看點

源碼分享:C++高性能的記憶體池實作。記憶體預配置設定,非複制構造,全局記憶體池。

為了實作面向對象程式設計,對于的複雜型結構快速構造與釋放,寫了個記憶體池管理模闆。他特點是允許使用者放棄記憶體池生成對象使用權,而不是執行析構。實作對象的複用。
  1. 實作同類型對象的全局化管理。無需顯示構造記憶體池。采用newOne宏申請對象。
  2. 記憶體塊的大小可調。記憶體池狀态可輸出顯示。
  3. 采用記憶體預配置設定方式。對象構造采用原始構造,非動态申請和複制構造,提高速度。
  4. 加鎖,實作多線程支援。(加鎖會額外耗費cpu時間,可設定宏

    CLMP_USE_LOCK_TYPE

    ,決定采用哪種方案)
  1. 通過giveUpOne()方法,放棄對象使用權,不需要釋放對象,實作快速對象複用。

示範代碼:應用案例: 【C++高速矩陣類實作】.

//定義任意類型,其構造含有動态記憶體的申請。
struct MyStruct
{
	int * c;
	string name;
	MyStruct(const char* lpName = "" )
		:c(new int[100]) , name(lpName)
	{	
		cout << "\nMyStruct 構造!: " << name << endl;
	}
	~MyStruct() {
		delete[] c;
		cout << "\nMyStruct 析構!  " << name << endl;
	}
};


int main() {

	auto p1 = newOne(MyStruct,"p1"); //申請一個對象,命名未p1

	giveUpOne(p1); //放棄使用權,不執行對象析構

	auto p2 = newOne(MyStruct,"p2"); //申請第二個對象,命名未p2

	if (p1 == p2) //由于giveUpOne調用,前後兩次newOne産生複用
		cout << "\np2 獲得了複用對象: " << p2->name << endl; 

	auto p3 = newOne(MyStruct, "p3"); //再申請一個對象
	
	// ...
	//使用完成後釋放對象,歸還到記憶體池
	deleteOne(p1); // 注意:此處應該避免繼續使用p1,因為他意見顯示放棄了使用權。
	deleteOne(p2); // 因為p2與p1儲存同一個對象指針,不會重複釋放。
	deleteOne(p3);

	getchar();
	return 1;
           

運作結果:

源碼分享:C++高性能的記憶體池實作。記憶體預配置設定,非複制構造,全局記憶體池。

模闆庫頭源碼:

CLMemPool.h

//DESIGNED BY CAILUO @2020-02-10 
//MINI-SUPPORT @ C++14

#pragma once

#ifndef __CL_MEMPOOL_H__
#define __CL_MEMPOOL_H__

#include <cassert>
#include <map>
#include <string>
#include <stdexcept>

#define CLMP_USE_LOCK_TYPE 0 // 0=無鎖(快),1=用C++鎖(慢),2=用windows臨界區鎖

#if CLMP_USE_LOCK_TYPE == 2
#include "windows.h" //windows平台,臨界區
class CLLock {
private:
	CRITICAL_SECTION cs;
public:
	CLLock() { InitializeCriticalSection(&cs); }
	~CLLock() { DeleteCriticalSection(&cs); }
	void lock() { EnterCriticalSection(&cs); }
	void unlock() { LeaveCriticalSection(&cs); }
};
#elif CLMP_USE_LOCK_TYPE == 1
#include <mutex> // C++ STL mutex
class CLLock {
private:
	std::mutex mt;
public:
	void lock() { mt.lock(); }
	void unlock() { mt.unlock(); }
};
#else
class CLLock {  //no use lock, it do nothing
public:
	void lock() {} 
	void unlock() {} 
};
#endif

#ifndef _CL_DIFVARS_SUPPORT_
#define _CL_DIFVARS_SUPPORT_
#ifdef UNICODE
typedef wchar_t Char;
#define tstring wstring
#ifndef _T
#define _T(x)  L ## x
#endif
#ifndef _tprintf_s
#define _tprintf_s wprintf_s
#define _stprintf_s swprintf_s
#define _tcscpy_s wcscpy_s
#endif
#else
typedef char Char;
#define tstring string
#ifndef _T
#define _T(x)  x
#endif
#ifndef _tprintf_s
#define _tprintf_s printf_s
#define _stprintf_s sprintf_s
#define _tcscpy_s strcpy_s
#endif
#endif
typedef const Char* PCStr;
typedef Char* PStr;
#ifndef BUFSIZE
#define BUFSIZE 256
#endif
#ifndef max
#define max(a,b) ((a) < (b) ? (b) : (a))
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif
#endif

template <typename classTag>
class CLMemPoolBlock;

template <typename classTag>
class CLMemPool;

記憶體池表類型
class MemPoolsTable
	:public std::map< CLMemPool<void*>*, std::tstring>,
	public CLLock
{};
//取得記憶體池表
inline MemPoolsTable* getMemPoolsTable() {
	static MemPoolsTable _mplst;
	return &_mplst;
}
增加記憶體池到記憶體池表
inline void addMemPoolToTable(PCStr name, CLMemPool<void*>* pMemPool)
{
	getMemPoolsTable()->lock();
	(*getMemPoolsTable())[pMemPool] = (name == nullptr ? _T("") : name);
	getMemPoolsTable()->unlock();
}

//記憶體池對象單元模闆類
template <typename classTag>
class CLMemPoolUnit {
	friend class CLMemPool<classTag>;
	friend class CLMemPoolBlock<classTag>;
public:
	struct DataHead {
		CLMemPoolUnit<classTag>* pPre;
		CLMemPoolUnit<classTag>* pNext;
		CLMemPoolBlock<classTag>* pThisBlock;
		bool bIsCreate;
		bool bIsUsed;
	};
private:
	DataHead hdr;
	classTag data;//包裹資料對象

	//在構造時候顯示調用
	CLMemPoolUnit<classTag>* init(
		CLMemPoolBlock<classTag>* _pThisBlock = 0,
		CLMemPoolUnit<classTag>* _pPre = 0,
		CLMemPoolUnit<classTag>* _pNext = 0,
		bool _isCreate = false,
		bool _isUsed = false
	) { 
		hdr.pThisBlock = _pThisBlock;
		hdr.pPre = _pPre;
		hdr.pNext = _pNext;
		hdr.bIsCreate = _isCreate;
		hdr.bIsUsed = _isUsed;
		return this; 
	}
	//注意:構造和析構函數用于顯示的調用來構造和析構内部包裹對象
	//他們不應該被系統調用,且内部不能有任何的資料處理過程;
	CLMemPoolUnit(){}
	template <typename... Args>
	CLMemPoolUnit(Args&&... args):data(std::forward<Args>(args)...){}
	~CLMemPoolUnit() {}
public:
	inline CLMemPoolBlock<classTag>* getOwnerBlock() {return hdr.pThisBlock;}
};

#define MUHEARDER( classTag, pData )  ((CLMemPoolUnit<classTag>*)(((char*)(pData))-(sizeof(CLMemPoolUnit<classTag>::DataHead))))

//記憶體池記憶體塊對象模闆類
template <typename classTag>
class CLMemPoolBlock {
	friend class CLMemPool<classTag>;
	friend class CLMemPoolUnit<classTag>;
private:
	explicit CLMemPoolBlock(size_t PerBlockMemCapacity_MB , CLMemPool<classTag>* _pOwnerMemPool)
	:pOwnerMemPool(_pOwnerMemPool)
	{
		init();
		alloc(PerBlockMemCapacity_MB * 1024 * 1024 / sizeof(CLMemPoolUnit<classTag>));
	}
	virtual ~CLMemPoolBlock() {
		releaseObjMenBlock();
	}
	//判斷該記憶體塊是否存在可用單元
	inline bool isUsable() {
		return pUsableLst ? true : false;
	}
	//将對象指針回收進入記憶體塊單元,如果對象是已經構造過的就調用标準析構。
	CLMemPoolUnit<classTag>* freeOneData(CLMemPoolUnit<classTag>* pUnit) {
		assert(pUnit !=nullptr);
		//執行對象析構
		if (pUnit->hdr.bIsCreate) {
			pUnit->CLMemPoolUnit<classTag>::~CLMemPoolUnit();
			pUnit->hdr.bIsCreate = false;
			nHasCreatedCounts--;
		}
		return putToUsable(pUnit);
	}
	//将對象指針回收進入記憶體塊單元,而不調用析構
	CLMemPoolUnit<classTag>* giveUpOneData(CLMemPoolUnit<classTag>* pUnit) {
		assert(pUnit != nullptr);
		//不執行對象析構,直接放入未用連條
		return putToUsable(pUnit);
	}
	//取出一個待命可用的對象單元,傳回其構造後的對象指針。注意:若申請時的目前配置設定對象已構造,則忽略構造傳參。
	template <typename... Args>
	classTag* getOneData(Args&&... args) {
		assert(pUsableLst != nullptr);
		if(!pUsableLst->hdr.bIsCreate) {
			//執行對象預設構造,這會構造内部包裹的資料類
			pUsableLst->CLMemPoolUnit<classTag>::CLMemPoolUnit(std::forward<Args>(args)...);
			pUsableLst->hdr.bIsCreate = true;
			nHasCreatedCounts++;
		}
		return putToUnusable(pUsableLst);
	}
	inline void init() {
		pUsableLst = 0;
		nMaxUsable = 0;
		pUnusableLst = 0;
		nMaxUnusable = 0;
		nHasCreatedCounts = 0;
		pPre = 0;
		pNext = 0;
		pMainDataLst = 0;
		nMaxDataCounts = 0;
	}
	//配置設定記憶體
	void alloc(size_t unitCounts = 1) {
		assert(pMainDataLst == 0 && pUsableLst == 0 && pUnusableLst == 0);
		if (pMainDataLst == 0) {
			//第一次申請記憶體空間
			pMainDataLst = (CLMemPoolUnit<classTag> *)malloc(sizeof(CLMemPoolUnit<classTag>)*(nMaxDataCounts = nMaxUsable = (unitCounts == 0 ? 1 : unitCounts)));
			//第一次執行可用隊列的初始化連接配接工作
			pUsableLst = &pMainDataLst[0];
			pMainDataLst[0].init(this, 0, nMaxDataCounts <= 1 ? 0 : &pMainDataLst[1]);
			for (size_t i = 1; i < nMaxDataCounts-1; ++i) {
				pMainDataLst[i].init(this, &pMainDataLst[i-1], &pMainDataLst[i + 1]);
			}
			pMainDataLst[nMaxDataCounts - 1].init(this, nMaxDataCounts <= 1 ? 0 : &pMainDataLst[nMaxDataCounts - 2], 0);
		}
	};
	//析構所有已經構造過的對象,但沒有使用的對象。
	void distructCreatedUsable() {
		if (nHasCreatedCounts == 0)
			return;
		//析構所有在可用連中的已構造
		for (CLMemPoolUnit<classTag>* pc = pUsableLst; pc != nullptr; ) {
			if (pc->hdr.bIsCreate) {
				pc->CLMemPoolUnit<classTag>::~CLMemPoolUnit();
				pc->hdr.bIsCreate = false;
				nHasCreatedCounts--;
			}
			pc = pc->hdr.pNext;
		}
	}
	//釋放記憶體
	void releaseObjMenBlock() {
		if (pMainDataLst) {
			//析構所有已使用的對象
			for (CLMemPoolUnit<classTag>* pc = pUnusableLst; pc != nullptr; ) {			
				pUnusableLst = freeOneData(pc);
				pc->init();
				pc = pUnusableLst;
			}
			//釋放動态記憶體
			free(pMainDataLst);
			pMainDataLst = 0;
		}		
	}
	//處理前後連接配接,隔離對象,傳回原對象指針
#define _extruct_pUnitBlock(pUnit) \
		((((pUnit)->pPre) ? ((pUnit)->pPre->pNext = (pUnit)->pNext) : 0),(((pUnit)->pNext)?((pUnit)->pNext->pPre = (pUnit)->pPre):0),(pUnit))
#define _extruct_pUnit(pUnit) \
		((((pUnit)->hdr.pPre) ? ((pUnit)->hdr.pPre->hdr.pNext = (pUnit)->hdr.pNext) : 0),(((pUnit)->hdr.pNext)?((pUnit)->hdr.pNext->hdr.pPre = (pUnit)->hdr.pPre):0),(pUnit))
	//對象放入可用隊列頭,傳回不可用隊列頭指針
	CLMemPoolUnit<classTag>*  putToUsable(CLMemPoolUnit<classTag>* pUnit) {
		assert(this == pUnit->hdr.pThisBlock);
		pUnit->hdr.bIsUsed = false;
		//處理不可用清單頭
		if (pUnusableLst && pUnusableLst == pUnit)
			pUnusableLst = pUnit->hdr.pNext;

		//處理前後連接配接,隔離對象
		_extruct_pUnit(pUnit);

		//接入可用清單
		if (pUsableLst) {pUsableLst->hdr.pPre = pUnit;}
		pUnit->hdr.pNext = pUsableLst;
		pUnit->hdr.pPre = 0;
		pUsableLst = pUnit;
		nMaxUnusable -= 1;
		nMaxUsable += 1;
		return pUnusableLst;
	}

	//傳回可用對象指針
	classTag*  putToUnusable(CLMemPoolUnit<classTag>* pUnit) {
		assert(this == pUnit->hdr.pThisBlock);
		pUnit->hdr.bIsUsed = true;
		//處理可用清單頭
		if (pUsableLst && pUsableLst == pUnit)
			pUsableLst = pUnit->hdr.pNext;

		//處理前後連接配接,隔離對象
		_extruct_pUnit(pUnit);
		
		//接入不可用清單
		if (pUnusableLst) {	pUnusableLst->hdr.pPre = pUnit;}
		pUnit->hdr.pNext = pUnusableLst;
		pUnit->hdr.pPre = 0;
		pUnusableLst = pUnit;
		nMaxUnusable += 1;
		nMaxUsable -= 1;
		return &pUnit->data;
	}
	CLMemPool<classTag>* const pOwnerMemPool; //所屬記憶體池
	CLMemPoolUnit<classTag>* pMainDataLst;//記憶體隊列
	size_t nMaxDataCounts;
	CLMemPoolUnit<classTag>* pUsableLst;//可用清單
	size_t nMaxUsable;
	CLMemPoolUnit<classTag>* pUnusableLst;//不可用清單
	size_t nMaxUnusable;
	size_t nHasCreatedCounts;
	CLMemPoolBlock<classTag>* pPre;
	CLMemPoolBlock<classTag>* pNext;
public:
	inline CLMemPool<classTag>* getOwnerMemPool() {	return pOwnerMemPool;}
};

//标準化接口
class IMenPool{
public:
	virtual void arrangement(bool) = 0;
	virtual void deallocateOne(void*) = 0;
	virtual void giveUpOne(void*) = 0;
};

//記憶體池對象模闆類。
 //請使用靜态的getMemPool()方法擷取唯一的記憶體池對象。
template <typename classTag> 
class CLMemPool :public IMenPool,public CLLock {
	friend class CLMemPoolBlock<classTag>; 
	friend class CLMemPoolUnit<classTag>;
private:
	//構造帶名稱辨別的目标類型記憶體池,加入記憶體池表。請勿顯示調用該構造方法。
	//請使用靜态的getMemPool()方法擷取唯一的記憶體池對象。
	CLMemPool(PCStr _lpTypeName, size_t PerBlockMemCapacity_MB = 5) :
		pEntry(nullptr),
		pCurrentUsingBlock(nullptr)
	{
		setPerBlockMemCapacity(PerBlockMemCapacity_MB);
		setMemPoolTypeName(_lpTypeName);
	}
	//構造目标類型記憶體池,加入記憶體池表。請勿顯示調用該構造方法。
	//請使用靜态的getMemPool()方法擷取唯一的記憶體池對象。	
	CLMemPool(size_t PerBlockMemCapacity_MB = 5) :
		pEntry(nullptr),
		pCurrentUsingBlock(nullptr)
	{
		setPerBlockMemCapacity(PerBlockMemCapacity_MB);
		setMemPoolTypeName(nullptr);
	}
public:
	PCStr lpTypeName;	
	virtual ~CLMemPool() {
		//不要釋放任何記憶體,而是做一次整理
		arrangement();
		getMemPoolsTable()->lock();
		for (auto  i = ::getMemPoolsTable()->find((CLMemPool<void*>*)this); 
			i != ::getMemPoolsTable()->end(); ){
			::getMemPoolsTable()->erase(i);
			break;
		} 
		getMemPoolsTable()->unlock();
	}
	void setMemPoolTypeName(PCStr _lpTypeName) {
		lpTypeName = _lpTypeName ;
		::addMemPoolToTable(lpTypeName, (CLMemPool<void*>*)this);//構造之後加入隊列
	}
	//整理記憶體,釋放目前沒有使用的空間歸還系統。該函數用于記憶體池反複使用後占用較大資源後做一次統一釋放。
	//distructCreatedButNoUsed = true 表示析構未被使用但已構造的對象
	virtual void arrangement(bool distructCreatedButNoUsed = true) {
		lock();
		pCurrentUsingBlock = nullptr;	//	置0
		for (CLMemPoolBlock<classTag>* pi = pEntry; pi != nullptr; )
		{
			CLMemPoolBlock<classTag>* pib = pi->pNext;
			if (distructCreatedButNoUsed)//是否析構未用對象
				pi->distructCreatedUsable();
			if (pi->nMaxUnusable == 0 && pi->nHasCreatedCounts == 0) { //釋放條件,沒有被使用,沒有已構造
				if (pEntry == pi)
					pEntry = pi->pNext;
				delete _extruct_pUnitBlock(pi);
			}
			pi = pib;
		}
		unlock();
	}
	//強行釋放所有記憶體。
	virtual void releaseObjMenPool() {
		lock();
		for (CLMemPoolBlock<classTag>* pi = pEntry; pi != nullptr; )
		{
			pCurrentUsingBlock = pi->pNext;
			delete pi; // 釋放塊
			pi = pCurrentUsingBlock;
		}
		m_PerBlockMemCapacity = 0;
		pEntry = 0;
		pCurrentUsingBlock = 0;
		unlock();
	}
	//向記憶體池儲備記憶體動态申請一個對象,若對象是已經構造過,就傳回指針,如果未構造,先構造并傳回其對象指針。
	//該方法接受可變參數構造方式傳參。
	//注意:若申請時的目前配置設定對象已構造過(比如:是由giveUpOne()放棄使用權而回收的對象),則忽略本次構造傳參。
	template <typename... Args>
	classTag* allocateOne(Args&&... args) {
		lock();		
		classTag* rt = getAvailableBlock()->getOneData(std::forward<Args>(args)...);
		unlock();
		return rt;
	}
	//向記憶體池釋放一個動态申請的對象,進行相關析構操作。
	virtual void deallocateOne(void* pDelete) {
		CLMemPoolUnit<classTag>* pUnit = MUHEARDER(classTag,pDelete);
		if(!checkPtrValidity(pUnit))return;//指針非法即傳回或抛異常
		lock();
		pUnit->hdr.pThisBlock->freeOneData(pUnit);
		unlock();
	}
	//向記憶體池釋放一個動态申請的對象,不析構。
	virtual void giveUpOne(void* pDelete) {
		CLMemPoolUnit<classTag>* pUnit = MUHEARDER(classTag, pDelete);
		if (!checkPtrValidity(pUnit))return;//指針非法即傳回或抛異常
		lock();
		pUnit->hdr.pThisBlock->giveUpOneData(pUnit);
		unlock();
	}
	//判斷指針是否屬于本記憶體池構造
	bool checkPtrValidity(CLMemPoolUnit<classTag>* pUnit){
		if(pUnit->hdr.pThisBlock->pOwnerMemPool != this)
			throw std::runtime_error("Tag obj is not created by this mem pool!");
		//if(pUnit < pUnit->hdr.pThisBlock->pMainDataLst || pUnit > pUnit->hdr.pThisBlock->pMainDataLst + pUnit->hdr.pThisBlock->nMaxDataCounts - 1)
		//	throw std::runtime_error("Tag obj is not created by this mem pool!");
		if (!pUnit->hdr.bIsUsed) {			
#ifdef _DEBUG
			if(pUnit->hdr.bIsCreate)
				throw std::runtime_error("Tag obj has been give up!");
			else
				throw std::runtime_error("Tag obj has been distructed!");
#else
			return false;
#endif
		}
		return true;
	}
	//設定單個記憶體塊的大小,機關MB,預設5MB
	virtual void setPerBlockMemCapacity(size_t PerBlockMemCapacity_MB = 5) {
		lock();
		m_PerBlockMemCapacity = PerBlockMemCapacity_MB == 0 ? 1 : PerBlockMemCapacity_MB;
		unlock();
	}
	//統計記憶體使用量,并控制向控台輸出目前記憶體池的記憶體使用情況。
	//bLog = true表示輸出資訊到控制台否則隻統計記憶體使用量,bDeTail = false表示采用簡化輸出,outInfoString動态資訊字元串内容需要手動釋放
	virtual size_t dumpInfo(bool bLog = true, bool bDeTail = false,PStr* outInfoString = nullptr) {
		std::tstring strAll;
#define dumpInfoMax 1000
		Char tem[dumpInfoMax];
		if (bLog || outInfoString) {
			if (bDeTail)
				_stprintf_s(tem, dumpInfoMax,_T("\r\n>>The MemmeryPool(=%s) Dumper Detail----------------------------------- \r\n>>MemBlock Info:\r\n"),(lpTypeName ? lpTypeName:_T("#UnkownTypeName")));
			else
				_stprintf_s(tem, dumpInfoMax,_T("\r\n>>The MemmeryPool(=%s) Dumper Simple----------------------------------- \r\n"), (lpTypeName ? lpTypeName : _T("#UnkownTypeName")));
			strAll += tem;
		}
		size_t si = 0;
		size_t siu = 0;
		size_t sit = 0;
		lock();
		for (const CLMemPoolBlock<classTag>* pc = pEntry; pc; )
		{
			si++;
			siu += pc->nMaxUnusable;
			sit += pc->nMaxDataCounts;
			size_t n = pc->nMaxDataCounts == 0 ? 0 : (pc->nMaxUnusable * 50) / pc->nMaxDataCounts;
			if ((bLog || outInfoString) && bDeTail) {
				_stprintf_s(tem, dumpInfoMax,_T(">>MemBlock(%zd): ["), si); strAll += tem;
				for (size_t i = 0; i < 50; ++i)
				{
					if (i < n)_stprintf_s(tem, dumpInfoMax,_T("*"));
					else _stprintf_s(tem, dumpInfoMax,_T("-"));
					strAll += tem;
				}
				_stprintf_s(tem, dumpInfoMax,_T("] <used=%zd%%>\r\n"), n * 2);
				strAll += tem;
			}
			pc = pc->pNext;
		}
		unlock();
		size_t perObj = sizeof(CLMemPoolUnit<classTag>);
		size_t mem = perObj*sit + si*sizeof(CLMemPoolBlock<classTag>);
		if (bLog || outInfoString) {
			size_t Tb = 0, Gb = 0, Mb = 0, Kb = 0, Byte = 0;
			Kb = mem / 1024; Byte = mem % 1024;
			Mb = Kb / 1024; Kb = Kb % 1024;
			Gb = Mb / 1024; Mb = Mb % 1024;
			Tb = Gb / 1024; Gb = Gb % 1024;
			if (Tb > 0)
				_stprintf_s(tem, dumpInfoMax,_T(">>Summary: mem= %zdT %zdG %zdM %zdK %zdB, blocks=%zd, total=%zd, used=%zd.\r\n\r\n"), Tb, Gb, Mb, Kb, Byte,  si, sit, siu);
			else if (Gb > 0)
				_stprintf_s(tem, dumpInfoMax,_T(">>Summary: mem= %zdG %zdM %zdK %zdB, blocks=%zd, total=%zd, used=%zd.\r\n\r\n"), Gb, Mb, Kb, Byte,  si, sit, siu);
			else if (Mb > 0)
				_stprintf_s(tem, dumpInfoMax,_T(">>Summary: mem= %zdM %zdK %zdB, blocks=%zd, total=%zd, used=%zd.\r\n\r\n"), Mb, Kb, Byte,  si, sit, siu);
			else if (Kb > 0)
				_stprintf_s(tem, dumpInfoMax,_T(">>Summary: mem= %zdK %zdB, blocks=%zd ,total=%zd, used=%zd.\r\n\r\n"), Kb, Byte,  si, sit, siu);
			else
				_stprintf_s(tem, dumpInfoMax,_T(">>Summary: mem= %zdB, blocks=%zd, total=%zd, used=%zd.\r\n\r\n"), Byte,  si, sit, siu);
			strAll += tem;
		}
		if (bLog)
			_tprintf_s(_T("%s"),strAll.c_str());
		if (outInfoString) {
			size_t nn = strAll.length() + 1;
			*outInfoString = new Char[nn];
			_tcscpy_s(*outInfoString, nn, strAll.c_str());
		}
		return mem;
	}
	//傳回記憶體使用量bytes
	size_t getMemSize() const { return dumpInfo(false, false, nullptr); }
private:
	CLMemPoolBlock<classTag>* pEntry;
	CLMemPoolBlock<classTag>* pCurrentUsingBlock;
	size_t m_PerBlockMemCapacity;

	//檢索清單取得可用的塊,沒有就建立
	CLMemPoolBlock<classTag>* getAvailableBlock() {
		if (pCurrentUsingBlock == nullptr) {
			if (pEntry == nullptr) {
				pCurrentUsingBlock = pEntry = new CLMemPoolBlock<classTag>(m_PerBlockMemCapacity, this);
			}
			else pCurrentUsingBlock = pEntry;
		}
		CLMemPoolBlock<classTag>* pStartBlock = pCurrentUsingBlock;
		//檢索可用的塊
		for (; pCurrentUsingBlock->isUsable() == false;)
		{
			if (pCurrentUsingBlock->pNext == nullptr) {
				if (pCurrentUsingBlock != pEntry) {
					pCurrentUsingBlock = pEntry;
				}
				else {
					pStartBlock = new CLMemPoolBlock<classTag>(m_PerBlockMemCapacity, this);
					if (pEntry->pNext)
						pEntry->pNext->pPre = pStartBlock;
					pStartBlock->pNext = pEntry->pNext;
					pEntry->pNext = pStartBlock;
					pCurrentUsingBlock = pStartBlock;
				}
			}
			else if (pCurrentUsingBlock->pNext == pStartBlock) {//插入新塊,在隊列中
				pStartBlock = new CLMemPoolBlock<classTag>(m_PerBlockMemCapacity, this);
				if (pCurrentUsingBlock->pNext)
					pCurrentUsingBlock->pNext->pPre = pStartBlock;
				pStartBlock->pNext = pCurrentUsingBlock->pNext;
				pCurrentUsingBlock->pNext = pStartBlock;
				pCurrentUsingBlock = pStartBlock;
			}
			else pCurrentUsingBlock = pCurrentUsingBlock->pNext;
		}
		return pCurrentUsingBlock;
	}
public:
	//取得類型對應的記憶體池對象
	static CLMemPool* getMenPool() {
		static CLMemPool _MenPool;
		return &_MenPool;
	}
	static CLMemPool* getMenPool(PCStr typeName) {
		CLMemPool* pc = getMenPool();
		if (pc->lpTypeName == nullptr && typeName != nullptr) {
			pc->setMemPoolTypeName(typeName);
		}
		return pc;
	}
	//向記憶體池動态申請一個對象,傳回對象指針。對應的,該指針必須用deleteOne釋放。也可用giveUpOne放棄使用權(該方式不執行對象析構)。
	//注意:若申請時的目前配置設定對象已構造過(比如:是由giveUpOne()放棄使用權而回收的對象),則忽略本次構造傳參。
	template <typename... Args>
	static classTag* newOneFromCLMemPool(PCStr name = nullptr, Args&&... args) {
		return (classTag*)getMenPool(name)->allocateOne(std::forward<Args>(args)...);
	}	
	//設定記憶體池中記憶體塊當個最大記憶體占用大小,機關MB
	static void setMemPoolBlockCapacity(size_t mb = 5) {
		assert(mb != 0);
		getMenPool()->setPerBlockMemCapacity(mb);
	}
};

//将由newOne獲得的對象指針釋放回記憶體池,會做相關析構操作。
inline void deleteOneBackToCLMemPool(void* pDelete) {
	assert(pDelete != nullptr);
	MUHEARDER(void*, pDelete)->getOwnerBlock()->getOwnerMemPool()->deallocateOne(pDelete);
}
//将由newOne獲得的對象指針放棄操作權,歸還放回記憶體池,但是不做析構操作。
inline void giveUpOneBackToCLMemPool(void* pDelete) {
	assert(pDelete != nullptr);
	MUHEARDER(void*, pDelete)->getOwnerBlock()->getOwnerMemPool()->giveUpOne(pDelete);
}

//目的:構造儲存typeName類型的記憶體池(如果未構造過的話),并傳回構造後的對象指針;
//作用:他向記憶體池動态申請一個對象(第一個參數是申請的類型,第二個參數可以是可變數量的構造參數),傳回對象指針。
//方法:對應的,該方法傳回的指針必須用deleteOne釋放,也可用giveUpOne放棄使用權(giveUpOne方式不執行對象析構,隻是把對象原樣放回記憶體池)。
//注意:該記憶體池采用預配置設定機制,可以高速的完成讀寫,但無法配置設定連續數量的對象(對象隊列),隻能配置設定單個對象。
//注意:若申請時的目前配置設定對象已構造過(比如:是由giveUpOne()放棄使用權而回收的對象),則忽略本次構造傳參。
#define newOne( typeName , ... ) (CLMemPool<typeName>::newOneFromCLMemPool(_T(#typeName) , __VA_ARGS__ ))
//生成代标号的記憶體池和對象指針的宏;并且指定記憶體池名稱(若名稱未被指定過的話)
#define newOneAndNamed( typeName, NameString , ... ) (CLMemPool<typeName>::newOneFromCLMemPool(_T(#NameString), __VA_ARGS__ ))
//删除對象,typeName是類型名,pObjToDelete是釋放的對象指針
#define deleteOne( pObjToDelete ) (deleteOneBackToCLMemPool((pObjToDelete)))
//放棄對象使用權(不會析構對象),并放回記憶體池待用,typeName是類型名,pObjToDelete是釋放的對象指針
#define giveUpOne( pObjToDelete ) (giveUpOneBackToCLMemPool((pObjToDelete)))

//整理所有記憶體池
inline void arrangeAllMemPools()
{
	getMemPoolsTable()->lock();
	for (auto& i : *getMemPoolsTable())
		i.first->arrangement();
	getMemPoolsTable()->unlock();
}
//輸出記憶體池表所有對象
inline size_t dumpMemPoolsTable(bool bLog = true, bool bDeTail = false,  PStr* outInfoString = nullptr)
{
	size_t mem = 0;
	PStr lpT = 0;
	std::tstring str, strh;
	if (bLog || outInfoString) {
		if (bDeTail)strh = _T("\r\n>>>>The MemmeryPool Table Dumper Detail----------------------------------- \r\n");
		else strh = _T("\r\n>>>>The MemmeryPool Table Dumper Simple----------------------------------- \r\n");
	}
	size_t ic = 1;
	Char cts[BUFSIZE];
	getMemPoolsTable()->lock();
	for (auto i = getMemPoolsTable()->cbegin(); i != getMemPoolsTable()->cend(); ic++)
	{
		size_t memc = (i->first->dumpInfo(false, bDeTail, ((bLog || outInfoString) ? &lpT : nullptr)));
		mem += memc;
		if (bLog || outInfoString) {
			if (i->first->lpTypeName)_stprintf_s(cts, _T("<MemPool(%zd)>, mem= %zd Bytes, type= %s \r\n"), ic, memc, i->second.c_str());
			else _stprintf_s(cts, _T("<MemPool(%zd)>, mem= %zd Bytes, %s \r\n"), ic, memc, _T("#UnkownTypeName"));
			strh += cts;
		}
		if (bLog || outInfoString) {
			if (lpT) {
				str += lpT;
				delete[] lpT;
				lpT = 0;
			}
		}
		++i;
	}
	if (bLog || outInfoString) {
		_stprintf_s(cts, _T(">>>>Total Mem = %zd Bytes \r\n\r\n>>>>Per MemmeryPool Information: \r\n"), mem);
		strh += cts;
		strh += str;
	}
	if (bLog)
		_tprintf_s(_T("%s"), strh.c_str());
	getMemPoolsTable()->unlock();
	if (outInfoString) {
		*outInfoString = new Char[strh.length() + 1];
		_tcscpy_s(*outInfoString, strh.length() + 1, strh.c_str());
	}
	return mem;
}

#endif
           

繼續閱讀