这个内存池模板,问题在什么地方呢?
下面是我的内存池模板,用来重载操作符new()delete(),提高效率
每次编译的时候没问题,运行以后提示访问越界
因为无法用Debug追踪,所以不清楚哪里有问题
之前我写了一个不用模板的版本,运行起来完全没有问题
这个版本仅仅是把有关内存池的操作抽象出来,想写一个通用的东西
大多数代码都是从上一个版本拷贝过来的:(
大虾帮我看看有什么问题?
另外我正在看清华区的release版本调试方法
哪位大虾可以给我介绍介绍自己的心得
我的编译环境VC++6.0 sp6
#if !defined(_MEMERY_POOL_H_INCLUDED_)
#define _MEMERY_POOL_H_INCLUDED_
//CMemoryPool模板
// 建立内存缓冲池重载new()delete(),以便提高频繁生成和释放的对象的性能
//由于Debug版new()和delete()有替代宏,所以CMemoryPool模板只能在release版
//下使用
// 以下代码建立内存缓冲池,并重载new()delete()
//
//class Cabc{
// ...
//#ifndef _DEBUG
//
// //内存缓冲池
// static CMemoryPool<Cabc> * m_pMemoryPool;
//
// //重载操作符new
// inline void * operator new(size_t nSize)
// { return m_pMemoryPool->alloc();};
//
// //重载操作符delete
// inline void operator delete(void * pMem, size_t nSize)
// { m_pMemoryPool->free(pMem);};
//
// //建立内存缓冲池
// static void MakeMemoryPool()
// { m_pMemoryPool = new CMemoryPool<Cabc>;};
//
// //释放内存缓冲池
// static void DeleteMemoryPool()
// { delete m_pMemoryPool; m_pMemoryPool=NULL;};
//#endif
// ...
//}
// 注意:
// 初始化静态成员,CMemoryPool<Cabc> * Cabc::m_pMemoryPool=NULL;
// 程序启动时调用MakeMemoryPool()
// 程序结束前调用DeleteMemoryPool()
template<class T>
class CMemoryPool
{
public:
CMemoryPool(unsigned int nSize = EXPANSION_SIZE)
: m_pNext(NULL)
{
Expand(nSize);
};
~CMemoryPool()
{
for(CMemoryPool<T> * pMem = m_pNext; pMem != NULL; pMem = m_pNext)
{
m_pNext = m_pNext->m_pNext;
delete[] pMem;
}
};
//分配内存
inline void * alloc()
{
//如果内存缓冲池耗尽,就进行拓展
if(!m_pNext) Expand();
//从内存缓冲池分配内存
CMemoryPool<T> * pHead = m_pNext;
m_pNext = pHead ->m_pNext;
return pHead;
};
//释放回收
inline void free(void * pElement)
{
//把用过的对象内存块加入内存缓冲池
CMemoryPool<T> * pHead = (CMemoryPool<T> *)pElement;
pHead ->m_pNext = m_pNext;
m_pNext = pHead;
};
private:
CMemoryPool<T> * m_pNext;
//拓展内存缓冲池一次申请对象的默认个数
enum{EXPANSION_SIZE = 32};
//拓展内存缓冲池
void Expand(int nExpansion = EXPANSION_SIZE)
{
//计算单位内存块的大小
size_t nSize = (sizeof(T) > sizeof(CMemoryPool<T> *))?
sizeof(T) : sizeof(CMemoryPool<T> *);
//添加一批内存块
CMemoryPool<T> * pMem = (CMemoryPool<T> *) new char[nSize];
m_pNext = pMem;
for(int i =0; i<nExpansion; i++)
{
pMem->m_pNext = (CMemoryPool<T> *) new char[nSize];
pMem = pMem->m_pNext;
}
pMem->m_pNext = NULL;
};
};
#endif // !defined(_MEMERYPOOL_H_INCLUDED_)
问题点数:50、回复次数:25Top
1 楼step_by_step(脚印)回复于 2004-09-04 17:40:57 得分 5
你是不是
class CDerived : public Cabc{};
然后 new CDerived??Top
2 楼joyfire(小地雷)回复于 2004-09-04 18:00:22 得分 0
没有,直接使用Cabc,
我程序里启动的时候用STL的list存储Cabc指针
和这个有关系吗?Top
3 楼joyfire(小地雷)回复于 2004-09-05 09:51:02 得分 0
自己顶一下Top
4 楼jk01dingxian(蓝光书虫~痛并快乐着~)回复于 2004-09-05 10:55:45 得分 0
不懂,学习,帮顶。Top
5 楼wwwooowww(熔点)回复于 2004-09-05 11:15:51 得分 5
我的一点认识,不知道对不对,你考虑一下:
你在构造函数:
CMemoryPool(unsigned int nSize = EXPANSION_SIZE)
: m_pNext(NULL)
{
Expand(nSize);
};
中调用一个类的成员函数,在构造函数运行前,你的对象还没有构造好。然而类的非静态成员一定要通过对象来调用,虽然没有写,但是实际是通过指向这个对象的this指针调用的。
this->Expand(nSize);//此时,对象还没有构造成功,所以this没有指向。
但是这时this所指的对象没有生成,所以是一个矛盾。所以出错。Top
6 楼wwwooowww(熔点)回复于 2004-09-05 11:17:01 得分 0
我的一个简单例子,编译不能通过:
#include <iostream>
using namespace std;
class A
{
private:
int *p;
public:
A(int n)
{
mall(n):
}
void mall(int n)
{
p = new int[n];
}
};
int main()
{
A a(10);
return 0;
}Top
7 楼step_by_step(脚印)回复于 2004-09-05 12:37:29 得分 0
to wwwooowww:
你的观点不对,你的代码之所以编译不过是因为mall(n)这一句后面应该是分号结尾,你用了冒号结尾了。
Top
8 楼classrect(以前的号丢了,郁闷)回复于 2004-09-06 09:10:53 得分 0
markTop
9 楼joyfire(小地雷)回复于 2004-09-06 09:18:06 得分 0
to wwwooowww
谢谢你的讨论,我觉得调用CMemoryPool构造函数时,已经可以调用Expand()
讲讲我的思路:
在前面的注释里面解释了这个模板的用法,在需要内存缓冲的Cabc类里加上一个
static CMemoryPool<Cabc> * m_pMemoryPool;
指针,然后在程序启动的时候需要调用下面方法建立内存缓冲池
static void MakeMemoryPool()
{ m_pMemoryPool = new CMemoryPool<Cabc>;};
这样当每次new Cabc()的时候会通过重载的
inline void * operator new(size_t nSize)
{ return m_pMemoryPool->alloc();};
从已经分配的内存池里得到内存,
对应的,调用delete把释放的空间放回内存池
Top
10 楼bm1408(向va_list学习~不用VC好多年~)回复于 2004-09-06 09:22:00 得分 5
然而类的非静态成员一定要通过对象来调用,?????
这句话不对!Top
11 楼joyfire(小地雷)回复于 2004-09-06 09:29:24 得分 0
下面这段代码是我第一版不用模板的代码,在VC6++ sp6编译通过
经过实验发现循环中间频繁new()和delete的程序,效率提高了80多倍
大虾对比一下上面的代码,帮我找找为什么上面的代码出问题
class Cabc{
...
// 以下代码建立内存缓冲池重载new()delete(),提高性能
//由于Debug版new()和delete()有替代宏,只能使用release版
// 注意:
// 初始化静态成员,Cabc::CMemoryList * Cabc::m_pPool=NULL;
// 程序启动时调用Cabc::MakeMemoryPool()
// 程序结束前调用Cabc::DeleteMemoryPool()
#ifndef _DEBUG
public:
class CMemoryList{
public:
CMemoryList * m_pNext;
};
void * operator new(size_t nSize)
{
if(!m_pPool) expand();
CMemoryList * pMemory = m_pPool;
m_pPool = pMemory->m_pNext;
return pMemory;
};
void operator delete(void * pDoomed, size_t nSize)
{
CMemoryList * pMemory = (CMemoryList *) pDoomed;
pMemory->m_pNext = m_pPool;
m_pPool = pMemory;
};
static void MakeMemoryPool()
{expand();};
static void DeleteMemoryPool()
{
for(CMemoryList * pMemory = m_pPool; pMemory != NULL; pMemory = m_pPool)
{
m_pPool = m_pPool->m_pNext;
delete[] pMemory;
}
m_pPool=NULL;
};
protected:
static void expand(int nExpansion = EXPANSION_SIZE)
{
if(m_pPool)
return;
size_t nSize = (sizeof(Cabc) > sizeof(CMemoryList *)) ?
sizeof(Cabc) : sizeof(CMemoryList *);
CMemoryList * pMemory = (CMemoryList *)new char[nSize];
m_pPool = pMemory;
for(int i = 0; i<nExpansion; i++)
{
pMemory->m_pNext = (CMemoryList *) new char[nSize];
pMemory = pMemory->m_pNext;
}
pMemory->m_pNext = NULL;
};
static CMemoryList * m_pPool;
enum{EXPANSION_SIZE = 32};
#endif
...
}Top
12 楼joyfire(小地雷)回复于 2004-09-06 15:04:42 得分 0
修正一个BUG,应该是,不过这个并不是程序出错的原因
上面那个不用模板的版本也一样要改
~CMemoryPool()
{
for(CMemoryPool<T> * pMem = m_pNext; pMem != NULL; pMem = m_pNext)
{
m_pNext = m_pNext->m_pNext;
delete[] (char*)pMem;//这里需要加一个(char*)否则内存泄漏
}
};
Top
13 楼joyfire(小地雷)回复于 2004-09-08 14:15:47 得分 0
自己顶一下Top
14 楼zfluo(云淡风清)回复于 2004-09-08 15:36:23 得分 5
你是不是在多线程的环境中使用啊?如果是的,需要加锁的Top
15 楼Mephisto_76((望美人如梦))回复于 2004-09-08 17:06:22 得分 5
不是很清楚,可能是因为Cabc里边语句static CMemoryPool<Cabc> * m_pMemoryPool;引起的吧?Top
16 楼joyfire(小地雷)回复于 2004-09-10 14:05:36 得分 0
是单线程环境,默认的new和delete是有线程安全机制的,但是这些锁降低了效率
正因为我确定自己的代码只在单线程下使用,所以才重载了new和delete。Top
17 楼joyfire(小地雷)回复于 2004-09-10 14:06:31 得分 0
to Mephisto_76 : 有什么问题呢?Top
18 楼Mephisto_76((望美人如梦))回复于 2004-09-10 17:59:02 得分 0
我自己的想法,不知道对不对。在这句中,由于Cabc还没有完全构造,而以Cabc为模板参数,我觉得可能不妥。Top
19 楼zfluo(云淡风清)回复于 2004-09-15 17:26:11 得分 5
内存池里的分配,改为用malloc和freeTop
20 楼nicknide(封月翔天)回复于 2004-09-15 18:16:37 得分 20
没有看完,不过鼓励楼主这种方法,将自己的代码帖出来,然后提个建议:
1:楼主,你的这种设计虽然是用的C++,但是还是基于C模式的,也就是说封装性体现的不是很好,也就是说还是离散的类的实例结构,对于客户,可以直接访问你的所有动态申请的接点,这个是危险的操作,如果有一段客户没有释放,那么这个内存就永远的丢失了……
建议是:用一个统一的类来管理内存,然后将这些分块记录在案,返回各个节点的同时,自己也加上一些保护,如此,一来调试的时候可以记录内存漏洞,二来可以执行全部回收以分配内存这样高级的操作,把泄露的内存收回;
2:你这里返回的是一个CMemoryPool<T> 的指针,但是这个指针是通过:new char[]分配的,但是你删除的时候是这样
delete[] pMem;
这是错误的,应该如此删除:
delete [](char*)pMem;
其实在这种场合,建议的方法是调用operator new(size);来分配内存
用operator delete(pMem)来回收,以防止歧义Top
21 楼nicknide(封月翔天)回复于 2004-09-15 18:21:36 得分 0
补充一点:
你分配内存的时候,依然是调用了很多次小的new操作,然后占有这些小的内存不释放,以后使用的时候就可以不用再次分配了,但是作为自己的堆来说的话,应该是一次分配一个大的空间,然后将大空间分成小空间来拍发,如此就可以更加提高效率。
不过这样以来,你回收和分发的时候,也要小心一些了,不能一次就把一个对象整个的分配出去,不过还是比较简单的……Top
22 楼nicknide(封月翔天)回复于 2004-09-15 18:27:23 得分 0
又发现一个问题:
但是楼主考虑的和我可能不一样,所以楼主给个你的应用的例子吧,越简单越好Top
23 楼joyfire(小地雷)回复于 2004-09-24 11:28:45 得分 0
谢谢你的指导,上个星期出差了,我马上把代码贴出来Top
24 楼joyfire(小地雷)回复于 2004-10-03 20:42:20 得分 0
//CMemoryPool模板
// 建立内存缓冲池重载new()delete(),以便提高频繁生成和释放的对象的性能
//由于Debug版new()和delete()有替代宏,所以CMemoryPool模板只能在release版
//下使用
// 以下代码建立内存缓冲池,并重载new()delete()
//
//class Cabc{
// ...
//#ifndef _DEBUG
//
// //内存缓冲池
// static CMemoryPool<Cabc> * m_pMemoryPool;
//
// //重载操作符new
// inline void * operator new(size_t nSize)
// { return m_pMemoryPool->alloc();};
//
// //重载操作符delete
// inline void operator delete(void * pMem, size_t nSize)
// { m_pMemoryPool->free(pMem);};
//
// //建立内存缓冲池
// static void MakeMemoryPool()
// { m_pMemoryPool = new CMemoryPool<Cabc>;};
//
// //释放内存缓冲池
// static void DeleteMemoryPool()
// { delete m_pMemoryPool; m_pMemoryPool=NULL;};
//#endif
// ...
//}
// 注意:
// 初始化静态成员,CMemoryPool<Cabc> * Cabc::m_pMemoryPool=NULL;
// 程序启动时调用MakeMemoryPool()
// 程序结束前调用DeleteMemoryPool()
};
CMemoryPool<Cabc> * Cabc::m_pMemoryPool=NULL;
MakeMemoryPool()
DeleteMemoryPool()
Top
25 楼joyfire(小地雷)回复于 2004-10-03 20:54:40 得分 0
前一篇帖子不小心提前按了确定,这一个是完成的用法说明
大虾指点
在abc.h里
class Cabc{
...
#ifndef _DEBUG
//内存缓冲池
static CMemoryPool<Cabc> * m_pMemoryPool;
//重载操作符new
inline void * operator new(size_t nSize)
{ return m_pMemoryPool->alloc();};
//重载操作符delete
inline void operator delete(void * pMem, size_t nSize)
{ m_pMemoryPool->free(pMem);};
//建立内存缓冲池
static void MakeMemoryPool()
{ m_pMemoryPool = new CMemoryPool<Cabc>;};
//释放内存缓冲池
static void DeleteMemoryPool()
{ delete m_pMemoryPool; m_pMemoryPool=NULL;};
#endif
...
}
在abc.cpp里
CMemoryPool<Cabc> * Cabc::m_pMemoryPool=NULL;
CApp::InitInstance()
{
#ifndef _DEBUG
//程序启动时调用
Cabc::MakeMemoryPool();
#endif
//这里使用cabc
...
#ifndef _DEBUG
//程序结束时调用
Cabc::DeleteMemoryPool()
#endif
}Top




