内存泄漏问题

xiaodong88 2003-06-24 01:18:58
一个程序,在debug是没有泄漏,但是在release下有泄漏?
请问各位大虾有哪些可能的原因,可惜程序在这里贴不下。
谢谢!
...全文
77 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
Richuen22 2003-07-09
  • 打赏
  • 举报
回复
1:或编译改为“优化最小文件”方式检查。
2:再试一下,Release方式下与bounderChecks联合编译,用F5来查看。
不过bounderChecks v6.5会误报资源文件有内存泄露。你用向导建一个对话框程序,什么都不加就编译为与bounderChecks联合,就知道是那里是误报。

sdp820101 2003-07-04
  • 打赏
  • 举报
回复
up
penter 2003-07-03
  • 打赏
  • 举报
回复
VC的编译优化会产生很多问题;
penter 2003-07-03
  • 打赏
  • 举报
回复
关闭 编译器 最优化 试试;
xiaodong88 2003-07-03
  • 打赏
  • 举报
回复
编译改为“4”级警告,用BounderCheck先是没有泄漏

release模式的时候不使用速度优化或大小优化,仅使用disable debug,仍然有泄漏
只是泄漏增加的速度减缓,我想是程序的运行速度降低的原因。
Richuen22 2003-06-27
  • 打赏
  • 举报
回复
将编译改为“4”级警告,再用BounderCheck查那里有内存泄露。
dev_uoboy 2003-06-27
  • 打赏
  • 举报
回复
这里提供一个解决方法,根据我分析,是由于编译器优化了你的代码而造成的。

一种简单的解决方法是,在编译release模式的时候不要使用速度优化或大小优化。

这样基本可以解决80%的debug下不泄漏,而在release下泄漏的问题。

如果懂汇编,那么可以用关键字将变量固定住,让编译器不优化你的特定变量。
ecc 2003-06-27
  • 打赏
  • 举报
回复
最近也碰到了好多莫名其妙的问题 debug版本运行会出问题 但是release版本就没问题
同时rebuild的

极其郁闷
xiaodong88 2003-06-26
  • 打赏
  • 举报
回复
to rtdb(东临碣石) : 哦,知道了,这种类型的语句我的程序里面没有。我通常用来判断指针是否为空。

现在用了free_card(痛并快乐着) 的方法,用_CrtMemCheckpoint()一步步跟踪,居然
str1.Format("%d",i)
这样的语句有内存扩大,请大家解释。

修改之后,这一块的内存扩大已经没有,但是其他地方较大的仍旧没有找到。
rtdb 2003-06-25
  • 打赏
  • 举报
回复
ASSERT()?
不是说仅能在debug下有用吗?

是呀, 所以若是在里面有什么语句,ASSERT(i=1)之类的
在RELEASE下就不会被执行。

那么RELEASE版和DEBUG版就不同了。
jvcit 2003-06-25
  • 打赏
  • 举报
回复
guan zhu
xiaodong88 2003-06-25
  • 打赏
  • 举报
回复
找了一个晚上仍旧没有找到。
xiaodong88 2003-06-24
  • 打赏
  • 举报
回复
ASSERT()?
不是说仅能在debug下有用吗?
寻开心 2003-06-24
  • 打赏
  • 举报
回复
也有可能是某些变量的初始化问题。
rtdb 2003-06-24
  • 打赏
  • 举报
回复
SORRY, 也可能是内存越界了。
rtdb 2003-06-24
  • 打赏
  • 举报
回复
虽说有点文不对题,但free_card(痛并快乐着) 说的好极了。

TO楼主: 若所说属实,问题必然出在某些DEBUG和RELEASE不同的语句上。
例如ASSERT()之类的。
free_card 2003-06-24
  • 打赏
  • 举报
回复
设置CRT报告样式
像以前描写的一样,按默认方式,_CrtDumpMemoryLeaks倾卸内存泄漏信息到输出窗口的Debug窗格。你可以运用_CrtSetReportMode重新设置它到堆存处,到另一个位置。如果你使用一个库,它可能重新设置输出到另一个位置。在这种情况下,你能够利用下面的说明来设置输出位置回到输出窗口:

_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );

关于使用_CrtSetReportMode去发送输出信息到另一个位置,要看Visual C++文件的_CrtSetReportMode节。


在内存分配数目处设置一个断点
在内存泄漏报告中的文件名和行号可告诉你泄漏的内存在那里被分配,但是了解内存在那里分配对于鉴定问题不总是充分的。在一个程序运行过程中,经常是一个分配将会被调用很多次,但是它可能在某次调用中泄漏内存。为了确定问题,你必须不但知道泄漏的内存在那里分配,还要知道泄漏发生的条件。对你来说,使它成为可能的那条信息是内存分配号。当那些被显示的时候,文件名和行号之后,这是在curly brace中出现的数值。例如,在下面的输出中,“18”是内存分配号。它的意思是泄漏的内存是你程序中内存分配的第十八个模块。

Detected memory leaks!

Dumping objects ->

C:\PROGRAM FILES\VISUAL STUDIO\MyProjects\leaktest\leaktest.cpp(20) : {18} normal block at 0x00780E80, 64 bytes long.

Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD

Object dump complete.


CRT库计算在程序运行期间分配的所用内存模块,包括CRT自己分配的内存或者诸如MFC的其它模块。因此带有分配号n的一个对象是在你的程序中分配的第n个对象,但不可能是由代码分配的第n个对象。(在大部分情况下,它是不会的。)

你可以利用分配号在内存分配的地方设置一个断点。为了做这些,你可以距离你的程序开始很近处,设置一个位置断点。当你的程序在那一点暂停时,你能够从QuickWatch对话框或者Watch窗口设置这样一个位置断点。例如,在Watch窗口中,在Name栏键入下面的表达式:

_crtBreakAlloc

如果你正在用CRT库的多线程的dynamic-link library (DLL)版本,你必须含有上下文操作符,像这里说明的:

{,,msvcrtd.dll}_crtBreakAlloc

现在,按RETURN。调试器评估调用并且把结果放置在Value栏。如果你在内存分配过程中还没有设置任何断点,那么这个值是-1。使用你想中断处内存分配的分配数值来代替Value表中的值——例如,18 去中断早期在输出过程中展现的分配.

当你在你感兴趣的内存分配处设置断点之后,你能够继续调试。在与从前相同的条件下,运行程序时一定要小心,因而分配的顺序不会改变。当你的程序在一个特殊的内存分配点中断的时候,你能够查看Call Stack窗口和其他的测试信息来确定在此条件下内存的分配。如果需要的话,你可以继续从那一点执行程序,以至于了解对象到底发生了什么事,同时还可能确定为了没有正确地被去分配。(对对象设置一个数据断点是很有帮助的。)

虽然在调试器中设置内存分配断点通常更加容易,但是如果你喜欢的话,你可以在你的代码中设置它们。为了在你的代码中设置一个内存分配断点,可以增加这样一行(对于第十八个内存分配):

_crtBreakAlloc = 18;

最为一个选择,你可以使用有相同效果的_CrtSetBreakAlloc函数。

_CrtSetBreakAlloc(18);

比较内存状态
定位内存泄漏的另一个方法就是在关键点对应用程序的内存状态做快照。CRT库提供了一个结构类型,_CrtMemState。你可以使用它来存储内存状态的一个快照。

_CrtMemState s1, s2, s3;

为了在特定点对内存状态进行快照,可以传递一个_CrtMemState结构到he _CrtMemCheckpoint函数。此函数用当时内存状态的一个快照来填充此结构:

_CrtMemCheckpoint( &s1 );

你可以通过传递此结构到_CrtMemDumpStatistics函数来倾卸_CrtMemState结构的任意点的内容:

_CrtMemDumpStatistics( &s3 );( &s1 );

此函数打印出类似于下面这样的一堆内存分配信息:

0 bytes in 0 Free Blocks.

0 bytes in 0 Normal Blocks.

3071 bytes in 16 CRT Blocks.

0 bytes in 0 Ignore Blocks.

0 bytes in 0 Client Blocks.

Largest number used: 3071 bytes.

Total allocations: 3764 bytes.

为了确定一个内存泄漏是否在一节代码中出现,你可以在此节前和此节后对内存状态作快照,然后用_CrtMemDifference比较两种状态:

_CrtMemCheckpoint( &s1 );

// memory allocations take place here

_CrtMemCheckpoint( &s2 );



if ( _CrtMemDifference( &s3, &s1, &s2) )

_CrtMemDumpStatistics( &s3 );


像名字暗示的一样,_CrtMemDifference比较两个内存状态(最先的两个参数)并且产生一个不同于这两个状态的结果(第三个参数)。在你的程序开始和结尾处的_CrtMemCheckpoint调用和使有_CrtMemDifference来比较结果为检测内存泄漏提供了另一种方法。如果一个泄漏被检测到,那么可以使用_CrtMemCheckpoint调用来分割你的程序并且使用二元binary search technique来定位泄漏。
xiaodong88 2003-06-24
  • 打赏
  • 举报
回复
release下运行时,耗用的内存资源不断增加;而debug 下没有增加。
free_card 2003-06-24
  • 打赏
  • 举报
回复
使用Microsoft Visual C++来检测和隔离内存泄漏
简介
具有动态的分配和释放内存的能力是C/C++程序语言的重要特色之一,但是中国的哲人孙子指出,最强有力的也是最脆弱的。对C/C++应用程序来说这当然是正确的,内存管理错误通常是bug起源之一。非常微妙且难于检测的bug之一就是内存 泄漏——不能正确地去分配已经分配了的内存。一个仅仅发生一次的轻微内存泄漏不可能引起注意,但是泄漏了大量内存或者日益增多的泄漏的程序可能表现出征兆,从可怜的(和慢慢地减少)性能到内存不足而完全失灵。更坏的是,一个有泄漏的程序可能占用很多的内存以至于导致另一个程序失灵,留给用户的只是对问题的一无所知。此外,一个严重的内存泄漏甚至可能是其他问题的征兆。

幸运的是,Visual C++ debugger 和 CRT库提供给你一系列有效的检测和鉴定内存泄漏的工具。这片文章阐述了如何使用这些工具去有效并系统的隔离内存泄漏。

设置内存泄漏检测
检测内存泄漏的基本工具是调试器和CRT调试堆函数。为了使用调试堆函数,在你的程序中你必须含有下面的说明:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include说明必须按顺序说明。如果你改变了顺序,你所用的函数可能不能正常工作。包含crtdbg.h的_malloc_dbg和 _free_dbg将 malloc和free函数映射到测试版中,它可以跟踪内存的分配和释放。这种映射仅仅在一个测试体系中发生(也就是说,仅仅当_DEBUG被定义的时候)。释放的体系使用通常的malloc和 free功能。

#define说明映射CRT堆函数的低级版本到相应的测试版本。这个说明是不需要的,但是没有它,内存泄漏处含有的只是没有多大用处的信息。

一旦你已经增加了刚才的说明,你能够通过在你的程序中包含下面的说明来释放内存信息:

_CrtDumpMemoryLeaks();
当你在调试情况下运行你的程序时,在输出窗口的Debug 标签处_CrtDumpMemoryLeaks表现出内存泄漏的信息。内存泄漏信息类似下面这样:

Detected memory leaks!

Dumping objects ->

C:\PROGRAM FILES\VISUAL STUDIO\MyProjects\leaktest\leaktest.cpp(20) : {18} normal block at 0x00780E80, 64 bytes long.

Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD

Object dump complete.


如果你没有用#define _CRTDBG_MAP_ALLOC说明,内存漏洞堆存处类似下面这样:

Detected memory leaks!

Dumping objects ->

{18} normal block at 0x00780E80, 64 bytes long.

Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD

Object dump complete.


像你所知道的,当_CRTDBG_MAP_ALLOC被定义时,_CrtDumpMemoryLeaks给了你更多的有用信息。如果_CRTDBG_MAP_ALLOC没有被定义,那么将向你如下显示:

内存分配数值(花括号内)
模块的类型(normal、client或者CRT)
以十六进制格式定位的内存
以字节计模块的大小
第一个十六字节的内容(也可以用十六进制)
当定义了_CRTDBG_MAP_ALLOC的时候,显示的内容也向你展现了出现泄漏内存所分配地方的文件。在文件名之后括号内的数字(20,以此为例)是文件内的行数值。如果你双击包含行数值和文件名的输出行,

C:\PROGRAM FILES\VISUAL STUDIO\MyProjects\leaktest\leaktest.cpp(20) : {18} normal block at 0x00780E80, 64 bytes long.

指针将会跳到源文件中内存被分配地方的行(在上面的情况下,leaktest.cpp的行号为20)。选择输出行并按F4将有同样的效果。

使用_CrtSetDbgFlag
如果你的程序总是在同一各地方存在,那么调用_CrtDumpMemoryLeaks时非常容易的。但是,如果你的程序需要在多个位置退出该怎么办?在每一个可能的出口处如果不调用_CrtDumpMemoryLeaks,你可在你的程序开始处包含下面的调用:

_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

当你的程序退出时,这个说明自动地调用_CrtDumpMemoryLeaks。你必须设置两个位域,_CRTDBG_ALLOC_MEM_DF和 _CRTDBG_LEAK_CHECK_DF,像以前说明的一样。

翻译内存模块的类型
像早期声明的一样,内存泄漏信息鉴别泄漏内存的每一个模块作为一个普通的模块、一个客户模块或者一个CRT模块。实际上,普通的模块和客户模块是你可能留心的唯一类型。

一个普通模块(normal block)是由你的程序分配的普通内存。
一个客户模块(client block)是一种特殊的内存模块,它由于需要一个析构函数的对象而被Microsoft Foundation Classes (MFC)所使用。MFC new操作子建立一个普通模块或者一个客户模块,来适合被创建的模块。
一个CTR模块是由CRT库提供自己使用而分配的内存模块。CRT库对这些模块来管理自己的去分配,因此你不可能在内存泄漏报告中注意到这些,除非有些地方有严重的错误(例如,CRT库崩溃)。
在内存泄漏信息中有两种你从来没有见过的模块类型:

空闲模块(free block)是一种被释放的内存模块Ignore block是你已经特殊标记过以至于在内存泄漏报告中不会出现的模块。


beijingshizi 2003-06-24
  • 打赏
  • 举报
回复
关键是在release下你怎么测试出来有泄漏的?
加载更多回复(5)

16,551

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧