您的位置:首页 > Web前端

关于一个与CString有关的RELEASE和DEBUG不同的问题

2010-03-21 11:28 363 查看
之前在工作中,需要解析大量的数据,当时使用了CString来存储字符数据,最后遇到了一个题目所示问题。具体情况是在DEBUG版本下编译后可以正常释放内存,但是同样的代码在REALEASE下内存却死活释放不了。有兴趣的朋友可以用如下代码试一下。我是在VC6.0基于MFC调试的,结果如我所遇到的情况。VS2008等其他平台我没有测试,不知道是不是还存在同样的问题。

 

如下的代码,只是在一个循环中不断的给一个cstring赋值,然后存储到一个数组中,再释放数组。

最终得到的现象是,如果是DEBUG模式,任务管理器看到的内存占用基本可以清除。

如果是RELEASE的话,基本没有把内存清掉。

 

 

CArray <CString,CString&> my;

int i = 0;
while(i < 100000)
{
CString str = "";
i++;
str.Format("%d-%d-%d-%d",i);
str += str;
my.Add(str);

}
AfxMessageBox("请查看没有释放内存");
my.RemoveAll();
my.FreeExtra();


 

 

然后,我又把string和int两种类型塞到CArray中,试试看是不是数组的原因,但是发现这两种情况都不存在此问题。

所以,猜测在这样频繁操作的情况下,CString可能在内存管理方面有些许问题。

在网友的帮助下查阅了这个帖子,收益匪浅。

http://topic.csdn.net/t/20050725/18/4167067.html#

 

把主要的贴出来给大家学习一下。(以下部分均为摘抄)

 

CString的内存管理在release模式采用堆的方式进行管理,不过对已经生成的堆在程序运行期间却没有释放机制。举个例子,程序在运行期间,如果需要解析文档,则需要生成的大量的CString对象,解析完毕后,程序释放了这些CString对象,但是MFC并没有释放CString所占用的内存,如果程序长期运行,则会造成大量的无效空间占用。    

 

CString的析构函数之所以这样写,是基于效率的考虑(当然,效率能提升多少就不好说了,就象MS把CView的IMPLEMENT_DYNCREATE和DECLARE_DYNCREATE放到不同的文件中以更改库链接粒度以降低link进项目的冗余代码量一样),CString对于buffer的分配和释放,均以64、128、256、512为单位进行,这使我想到了ms在file   system中使用的lazy   write方案和驱动中经常使用的lookside   list。我的想法是,ms在设计的时候可能认为string是一种经常要动态调整大小的类,尽管x86是段页式离散内存管理,但是一个页4K,一个CString大部分时候都占用不了那么多空间,如果象debug版那样FreeData即等于delete   buffer,一段时间下来堆中会留下很多内部碎片,这对于内存管理非常不利,所以才把它设计成这个样子。  
  另外,我查看过.net的CString,实现方法有了很大改变,增加了AfxStringMgr类。时间仓促没有仔细看,可能是解决了楼主的问题。虽然重编译MFC库是可以的,但是这样就丧失了dll的初衷,不值得提倡。  
  最后我有一个建议,既然知道了MFC的CString对内存的管理是以64、128、256、512进行,而且你的程序会大量生成CString对象,为什么你就不能在程序里做到每次要用到CString的时候,确保其中字符个数大于512或者正好等于64、128、256、512呢?只要是大于512的CString,FreeData的动作正是你想要的,反过来说,即使你不使用CString,而是一下子new出1000个长度<10的char数组,照样也会增加内存消耗的。当然也可以试试别的方案,譬如.net的新版CString及std::string。

 

总之讨论下来结果有4:  
  1,改用.net的CString或者使用托管。  
  2,rebuild   MFC  
  3,rewrite   CString   and   repalce   it。  
  4,确保每次字符个数>512。  

 

个人认为,在如此频繁操作的情况下,直接避开CString而使用string是最简单的方法了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息