关于一个与CString有关的RELEASE和DEBUG不同的问题
2010-03-21 11:28
363 查看
之前在工作中,需要解析大量的数据,当时使用了CString来存储字符数据,最后遇到了一个题目所示问题。具体情况是在DEBUG版本下编译后可以正常释放内存,但是同样的代码在REALEASE下内存却死活释放不了。有兴趣的朋友可以用如下代码试一下。我是在VC6.0基于MFC调试的,结果如我所遇到的情况。VS2008等其他平台我没有测试,不知道是不是还存在同样的问题。
如下的代码,只是在一个循环中不断的给一个cstring赋值,然后存储到一个数组中,再释放数组。
最终得到的现象是,如果是DEBUG模式,任务管理器看到的内存占用基本可以清除。
如果是RELEASE的话,基本没有把内存清掉。
然后,我又把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是最简单的方法了。
如下的代码,只是在一个循环中不断的给一个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是最简单的方法了。
相关文章推荐
- 【转】VC下关于debug和release的不同的问题总结
- VC下关于debug和release的不同的问题总结
- 遇到一个debug版本和release版本运行结果不同的问题
- 记录一个问题:win32程序release版本和debug版本运行效果不同
- 关于Debug版正常运行,release版运行崩溃的问题
- 关于visual studio(vs)debug和release问题
- Debug 模式 和 Release 模式下,一个线程在"编译"上引发的问题
- 关于Objective-C 对象release操作的一个小问题探讨
- VC下关于debug和release的不同的讨论(收藏-转载)
- 关于不同版本软件复用同一个脚本的问题
- VC下关于debug和release的不同的讨论
- 编译dll时debug和release版命名不同遇到的问题
- 关于如何判断程序和类库是Debug 还是 Release 的问题
- 关于Objective-C 对象release操作的一个小问题探讨
- opencv下关于debug和release的切换报错问题
- 如何让一个动态链接库文件debug和release编译的时候生成不同的文件名
- debug和release编译结果在多线程的遇到的一个问题
- 有关一个 iframe 的问题,关于在 iframe 内的页面内登录成功后,如何由当前页直接转到另一个页面内?
- VC下关于debug和release的不同的讨论
- 关于Android DES加密算法在不同平台加密结果不同的问题的一个解决方法