最近在写一个IOCP扩展类,遇到内存池问题,网上的完整代码不多,可惜没钱下载,只能自己研究了,自己写了份代码,实现了基本功能,自动增加内存块,可实现较大吞吐量。代码分享出来,请大家交流,帮助优化。目前还只能实现单个对象的管理,大神请指点。
先来看性能对比结果,见下图(代码在后面,可能微博识别的原因导致贴上来后代码有些错误,自己调整):
Release模式下,反复循环处理总计5200万个对象,传统new/delete操作花4.29秒,内存池操作花2.1秒,大约是传统new/delete一半时间(若测试方案不同,测试规模增大,速度优势越明显)。
本例中,内部维护了64个块(每个块5mb),总计320Mb,可用单元524万个单元,已用了161万个单元,内存池的内存使用情况和结构由dumpInfo输出,
头文件:
#pragma once
#ifndef __CL_OBJMEMPOOL_H__
#define __CL_OBJMEMPOOL_H__
//内部锁类,基类
class CLCSLock
{
public:
CLCSLock(void);
~CLCSLock(void);
//主锁,请用于线程队列的增加删除操作
void lock();
void unLock();
protected:
private:
CRITICAL_SECTION *m_cs = 0;
};
template <</span>typename classTag>
class CLObjMenBlock;
template <</span>typename classTag>
class CLObjMenPool;
//内存池对象单元模板类
template <</span>typename classTag>
class CLObjMenUnitInfo
{
friend class CLObjMenPool;
friend class CLObjMenBlock;
friend class CLObjMenUnitInfo;
public:
classTag data;
protected:
CLObjMenUnitInfo *pPre;
CLObjMenUnitInfo *pNext;
CLObjMenBlock *pThisBlock;
//在构造时候显示调用
CLObjMenUnitInfo *init(
CLObjMenBlock *_pThisBlock = 0,
CLObjMenUnitInfo *_pPre = 0,
CLObjMenUnitInfo *_pNext = 0)
{
pThisBlock = _pThisBlock;
pPre = _pPre;
pNext = _pNext;
return this;
}
};
//内存池内存块对象模板类
template <</span>typename classTag>
class CLObjMenBlock
{
friend class CLObjMenPool;
friend class CLObjMenBlock;
friend class CLObjMenUnitInfo;
protected:
CLObjMenBlock(DWORD_PTR PerBlockMemCapacity_MB)
{
init();
alloc(PerBlockMemCapacity_MB * 1024 * 1024 / sizeof(CLObjMenUnitInfo));
}
~CLObjMenBlock()
{
release();
init();
}
//判断该内存块是否存在可用单元
inline BOOL isUsable()
{
return pUsableLst ? TRUE : FALSE;
}
//将对象指针回收进入内存块单元
CLObjMenUnitInfo *freeOneData(CLObjMenUnitInfo *pUnit)
{
assert(pUnit != NULL);
//执行对象析构
(&(pUnit->data))->classTag::~classTag();
return putToUsable(pUnit);
}
//取出一个待命可用的对象单元,返回其构造后的对象指针
classTag *getOneData()
{
assert(pUsableLst != NULL);
//执行对象默认构造
pUsableLst->CLObjMenUnitInfo::CLObjMenUnitInfo();
return putToUnusable(pUsableLst);
}
inline void init()
{
pUsableLst = 0;
nMaxUsable = 0;
pUnusableLst = 0;
nMaxUnusable = 0;
pPreBlock = 0;
pNextBlock = 0;
pMainDataLst = 0;
nMaxDataCounts = 0;
}
//分配内存
void alloc(DWORD_PTR unitCounts = 1)
{
assert(pMainDataLst == 0 && pUsableLst == 0 && pUnusableLst == 0);
if (pMainDataLst == 0)
{
//第一次申请内存空间
pMainDataLst = (CLObjMenUnitInfo *)malloc(sizeof(CLObjMenUnitInfo) * (nMaxDataCounts = nMaxUsable = (unitCounts == 0 ? 1 : unitCounts)));
//第一次执行可用队列的初始化连接工作
pUsableLst = &pMainDataLst[0];
pMainDataLst[0].init(this, 0, nMaxDataCounts <= 1 ? 0 : &pMainDataLst[1]);
for (DWORD_PTR 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 release()
{
if (pMainDataLst)
{
//析构所有已使用的对象
for (CLObjMenUnitInfo *pc = pUnusableLst; pc != NULL; )
{
pUnusableLst = freeOneData(pc);
pc->init();
pc = pUnusableLst;
}
//释放动态内存
free(pMainDataLst);
pMainDataLst = 0;
}
}
//对象放入可用队列头,返回不可用队列头指针
CLObjMenUnitInfo *putToUsable(CLObjMenUnitInfo *pUnit)
{
assert(this == pUnit->pThisBlock);
//处理不可用列表头
if (pUnusableLst && pUnusableLst == pUnit)
pUnusableLst = pUnit->pNext;
//处理前后连接,隔离对象
extruct(pUnit);
//接入可用列表
if (pUsableLst)
{
pUsableLst->pPre = pUnit;
}
pUnit->pNext = pUsableLst;
pUnit->pPre = 0;
pUsableLst = pUnit;
nMaxUnusable -= 1;
nMaxUsable += 1;
return pUnusableLst;
}
//返回可用对象指针
classTag *putToUnusable(CLObjMenUnitInfo *pUnit)
{
assert(this == pUnit->pThisBlock);
//处理可用列表头
if (pUsableLst && pUsableLst == pUnit)
pUsableLst = pUnit->pNext;
//处理前后连接,隔离对象
extruct(pUnit);
//接入不可用列表
if (pUnusableLst)
{
pUnusableLst->pPre = pUnit;
}
pUnit->pNext = pUnusableLst;
pUnit->pPre = 0;
pUnusableLst = pUnit;
nMaxUnusable += 1;
nMaxUsable -= 1;
return &pUnit->data;
}
//处理前后连接,隔离对象
inline void extruct(CLObjMenUnitInfo *pUnit)
{
if (pUnit->pPre)
{
pUnit->pPre->pNext = pUnit->pNext;
}
if (pUnit->pNext)
pUnit->pNext->pPre = pUnit->pPre;
}
CLObjMenUnitInfo *pMainDataLst;
DWORD_PTR nMaxDataCounts;
CLObjMenUnitInfo *pUsableLst;
DWORD_PTR nMaxUsable;
CLObjMenUnitInfo *pUnusableLst;
DWORD_PTR nMaxUnusable;
CLObjMenBlock *pPreBlock;
CLObjMenBlock *pNextBlock;
};
//内存池对象模板类
template <</span>typename classTag>
class CLObjMenPool
{
friend class CLObjMenPool;
friend class CLObjMenBlock;
friend class CLObjMenUnitInfo;
public:
CLObjMenPool(DWORD_PTR PerBlockMemCapacity_MB = 5)
{
setPerBlockMemCapacity(PerBlockMemCapacity_MB);
pEntry = 0;
pCurrentUsingBlock = 0;
}
~CLObjMenPool()
{
for (CLObjMenBlock *pi = pEntry; pi != NULL; )
{
pCurrentUsingBlock = pi->pNextBlock;
delete pi; // 释放块
pi = pCurrentUsingBlock;
}
m_PerBlockMemCapacity = 0;
pEntry = 0;
pCurrentUsingBlock = 0;
}
//向内存池动态申请一个对象,构造并返回其指针
classTag *newOne()
{
if (pEntry == NULL)
{
pCurrentUsingBlock = pEntry = new CLObjMenBlock(m_PerBlockMemCapacity);
}
CLObjMenBlock *pStartBlock = pCurrentUsingBlock;
//检索可用的块
for (; pCurrentUsingBlock->isUsable() == FALSE;)
{
if (pCurrentUsingBlock->pNextBlock == NULL)
{
if (pCurrentUsingBlock != pEntry)
{
pCurrentUsingBlock = pEntry;
}
else
{
pStartBlock = new CLObjMenBlock(m_PerBlockMemCapacity);
if (pEntry->pNextBlock)
pEntry->pNextBlock->pPreBlock = pStartBlock;
pStartBlock->pNextBlock = pEntry->pNextBlock;
pEntry->pNextBlock = pStartBlock;
pCurrentUsingBlock = pStartBlock;
}
}
else if (pCurrentUsingBlock->pNextBlock == pStartBlock) //插入新块,在队列中
{
pStartBlock = new CLObjMenBlock(m_PerBlockMemCapacity);
if (pCurrentUsingBlock->pNextBlock)
pCurrentUsingBlock->pNextBlock->pPreBlock = pStartBlock;
pStartBlock->pNextBlock = pCurrentUsingBlock->pNextBlock;
pCurrentUsingBlock->pNextBlock = pStartBlock;
pCurrentUsingBlock = pStartBlock;
}
else pCurrentUsingBlock = pCurrentUsingBlock->pNextBlock;
}
return pCurrentUsingBlock->getOneData();
}
//向内存池释放一个动态申请的对象,进行相关析构操作
void deleteOne(CLObjMenUnitInfo *pDelete)
{
assert(pDelete->pThisBlock != NULL);
pDelete->pThisBlock->freeOneData(pDelete);
}
//设置单个内存块的大小,单位MB,默认5MB
void setPerBlockMemCapacity(DWORD_PTR PerBlockMemCapacity_MB = 5)
{
m_PerBlockMemCapacity = PerBlockMemCapacity_MB == 0 ? 1 : PerBlockMemCapacity_MB;
}
//统计内存使用量,并控制向控台输出当前内存池的内存使用情况。
//bLog = TRUE表示输出信息到控制台否则只统计内存使用量,bDeTail = FALSE表示采用简化输出
DWORD_PTR dumpInfo(BOOL bLog = TRUE, BOOL bDeTail = FALSE)
{
if (bLog)
{
if (bDeTail)
_tprintf_s(_T("\n>>The Memmery pool dumper detail--------------------------------- \n\n>>MemBlock Info:\n"));
else
_tprintf_s(_T("\n>>The Memmery pool dumper simple--------------------------------- "));
}
size_t si = 0;
size_t siu = 0;
size_t sit = 0;
for (const CLObjMenBlock *pc = pEntry; pc; )
{
si++;
siu += pc->nMaxUnusable;
sit += pc->nMaxDataCounts;
size_t n = pc->nMaxDataCounts == 0 ? 0 : ((double)pc->nMaxUnusable) / pc->nMaxDataCounts * 50.0;
if (bLog && bDeTail)
{
_tprintf_s(_T(">>MemBlock(%zd): ["), si);
for (size_t i = 0; i < 50; i++)
{
if (i < n)_tprintf_s(_T("*"));
else _tprintf_s(_T("-"));
}
_tprintf_s(_T("] \n"), n * 2);
}
pc = pc->pNextBlock;
}
DWORD_PTR perObj = sizeof(CLObjMenUnitInfo);
DWORD_PTR mem = perObj * sit + si * sizeof(CLObjMenBlock);
if (bLog)
{
DWORD_PTR 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)
_tprintf_s(_T("\n>>Summary: mem=%zdT %zdG %zdM %zdK %zdB, blocks=%zd, total=%zd, used=%zd.\n"), Tb, Gb, Mb, Kb, Byte, si, sit, siu);
else if (Gb > 0)
_tprintf_s(_T("\n>>Summary: mem=%zdG %zdM %zdK %zdB, blocks=%zd, total=%zd, used=%zd.\n"), Gb, Mb, Kb, Byte, si, sit, siu);
else if (Mb > 0)
_tprintf_s(_T("\n>>Summary: mem=%zdM %zdK %zdB, blocks=%zd, total=%zd, used=%zd.\n"), Mb, Kb, Byte, si, sit, siu);
else if (Kb > 0)
_tprintf_s(_T("\n>>Summary: mem=%zdK %zdB, blocks=%zd ,total=%zd, used=%zd.\n"), Kb, Byte, si, sit, siu);
else
_tprintf_s(_T("\n>>Summary: mem=%zdB, blocks=%zd, total=%zd, used=%zd.\n"), Byte, si, sit, siu);
}
return mem;
}
protected:
CLObjMenBlock *pEntry;
CLObjMenBlock *pCurrentUsingBlock;
DWORD_PTR m_PerBlockMemCapacity;
};
//全局的安全锁
extern CLCSLock _g_memPoolGLock;
//全局的安全锁
inline CLCSLock &getGlobleMemPoolLocker()
{
return _g_memPoolGLock;
}
//取得类型对应的内存池对象
template <</span>typename classTag>
CLObjMenPool *getMenPool()
{
static CLObjMenPool _MenPool;
return &_MenPool;
}
//向内存池动态申请一个对象,返回对象指针。对应的,该指针必须用deleteOne释放
template <</span>typename classTag>
classTag *newOne()
{
getGlobleMemPoolLocker().lock();
classTag *rt = getMenPool()->newOne();
getGlobleMemPoolLocker().unLock();
assert(rt != NULL);
return rt;
}
//将由newOne获得的对象指针释放回内存池,会做相关析构操作
template <</span>typename classTag>
void deleteOne(classTag *pDelete = 0)
{
assert(pDelete != NULL);
getGlobleMemPoolLocker().lock();
getMenPool()->deleteOne((CLObjMenUnitInfo *)pDelete);
getGlobleMemPoolLocker().unLock();
}
//设置内存池中内存块当个最大内存占用大小,单位MB
template <</span>typename classTag>
void setMemPoolBlockCapacity(DWORD_PTR mb = 5 )
{
assert(mb != 0);
getGlobleMemPoolLocker().lock();
getMenPool()->setPerBlockMemCapacity(mb);
getGlobleMemPoolLocker().unLock();
}
#endif
cpp文件:
#include"CLObjectMemPool.h"
//全局唯一的线程池锁对象
CLCSLock _g_memPoolGLock;
CLCSLock::CLCSLock(void)
{
if (m_cs == 0)
{
m_cs = new CRITICAL_SECTION;
if (m_cs) InitializeCriticalSection(m_cs);
else throw std::logic_error("CriticalSection didn't alloc!");
}
}
CLCSLock::~CLCSLock(void)
{
if (m_cs)
{
DeleteCriticalSection(m_cs);
delete m_cs;
m_cs = 0;
}
}
void CLCSLock::lock()
{
if(m_cs)EnterCriticalSection(m_cs);
else throw std::logic_error("CriticalSection didn't alloc!");
}
void CLCSLock::unLock()
{
if (m_cs)LeaveCriticalSection(m_cs);
else throw std::logic_error("CriticalSection didn't alloc!");
}
测试代码,其中CLString是我自定义的一个类:
int main() // BHV test
{
_tprintf_s(_T("\n Mem Pool Test: "));
size_t mb = 200;//单次连续申请内存200 MB
size_t cycleTimes = 10;//循环次数
size_t si = (double)mb * 1024 * 1024 / sizeof(CLString);
PCLString *plst = new PCLString[si];
ZeroMemory(plst, si * sizeof(PCLString));
ULONGLONG st = GetTickCount64();
for (size_t j = 0; j < cycleTimes; j++)
{
for (size_t i = 0; i < si; i++)
{
if (plst[i] == 0) plst[i] = new CLString;
}
for (size_t i = 0; i < si; i++)
{
if (plst[i] != 0)delete plst[i];
plst[i] = 0;;
}
}
ULONGLONG et = GetTickCount64();
ZeroMemory(plst, si * sizeof(PCLString));
//设置单个块最大10Mb
//setMemPoolBlockCapacity(10);
ULONGLONG st2 = GetTickCount64();
for (size_t j = 0; j < cycleTimes; j++)
{
for (size_t i = 0; i < si; i++)
{
if (plst[i] == 0)plst[i] = newOne();
}
for (size_t i = 0; i < si; i++)
{
if (plst[i] != 0)deleteOne(plst[i]);
plst[i] = 0;
}
}
ULONGLONG et2 = GetTickCount64();
_tprintf_s(_T("\n\n对比结果: 处理对象数 = %zd, new/delete操作 = %zdms, MemPool操作 = %zdms. \n\n"), si * cycleTimes, et - st, et2 - st2);
for (size_t i = 0; i < si / 3.25; i++)
{
if (plst[i] == 0)plst[i] = newOne();
}
getMenPool()->dumpInfo(1, 1); //采用详细输出
for (size_t i = 0; i < si / 3.25; i++)
{
if (plst[i] != 0)deleteOne(plst[i]);
plst[i] = 0;
}
delete[] plst;
return 0;
}
来源:https://blog.csdn.net/carlclouder/article/details/101264830