CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
可用分押宝游戏火热进行中... 专题改版:Java Web 专题
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  C/C++ >  C++ 语言

这个内存池模板,问题在什么地方呢?

楼主joyfire(小地雷)2004-09-04 15:29:28 在 C/C++ / C++ 语言 提问

下面是我的内存池模板,用来重载操作符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

相关问题

  • 什么地方用双通道内存?
  • 函数模板错在什么地方了~~~
  • “在引用模板名称的地方,必须伴有该模板的参数列表” 请问如何理解?
  • 我该在什么地方释放内存
  • 关于类模板的问题,在实例化为string时会出现内存不能为read的错误,望高手能解决一下。
  • 高分求内存池c源码
  • 模板问题
  • 关于模板
  • 模板问题?????
  • 寻找模板!

关键词

  • 内存
  • 模板
  • 代码
  • 指针
  • 函数
  • cmemorypool
  • pmemorypool
  • cabc
  • pmem
  • pnext

得分解答快速导航

  • 帖主:joyfire
  • step_by_step
  • wwwooowww
  • bm1408
  • zfluo
  • Mephisto_76
  • zfluo
  • nicknide

相关链接

  • C/C++ Blog
  • C/C++类图书
  • C/C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
世纪乐知(北京)网络技术有限公司 版权所有, 京 ICP 证 020026 号
北京创新乐知广告有限公司 提供技术支持
Copyright © 2000-2007, CSDN.NET, All Rights Reserved
GongshangLogo