结束程序时候,vc的输出如下:
Detected memory leaks!
Dumping objects ->
{20616} normal block at 0x07FD28D0, 152 bytes long.
 Data: <                > 8F 00 00 00 B0 02 00 00 90 00 00 00 B3 02 00 00 
{20615} normal block at 0x07FD2840, 80 bytes long.
 Data: <                > 98 00 00 00 9C 02 00 00 94 00 00 00 9F 02 00 00 
{20614} normal block at 0x07FD2778, 136 bytes long.
 Data: <                > 92 00 00 00 94 02 00 00 95 00 00 00 90 02 00 00 
{20613} normal block at 0x07FD26E8, 80 bytes long.
 Data: <                > 8C 00 00 00 94 02 00 00 8C 00 00 00 96 02 00 00 
{20612} normal block at 0x07FD2678, 48 bytes long.
 Data: <    X       X   > 9A 02 00 00 58 02 00 00 9D 02 00 00 58 02 00 00 
{20611} normal block at 0x07FD25B8, 128 bytes long.
.................
请问高人们,如何察看是哪里的代码造成的?

解决方案 »

  1.   

    有没有设么好点的内存泄露检测工具阿?
    BoundsChecker的使用方便么?我查了几个帖子,好像用起来不是很简单!
      

  2.   

    有几种显示方式,有的是会直接显示出行的。楼主这样的显示,不能直接定位。可以根据normal   block   at   0x07FD26E8里面的0x07FD26E8地址,配合编译生成的map文件,分析出泄露的位置
      

  3.   

    通过这个内存块的编号{20616} 可以查看。根据内存分配编号设置断点:   
        内存泄漏报告中的文件名和行数告诉你内存泄漏的位置,但是知道内存泄漏位置不是总是能找到问题所在。在一个运行的程序中一个内存分配操作可能被调用多次,但是内存泄漏可能只发生在其中的某次操作中。为了确认问题所在,你除了知道泄漏的位置之外,你还必须要知道发生泄漏的条件。内存分配编号使得解决这个问题成为可能。这个数字就在文件名、行数之后的大括弧内。例如,在上面的输出中“18”就是内存分配编号,它的意思是你程序中的内存泄漏发生在第18次分配操作中。   
        CRT库对正在运行程序中所有的内存块分配进行计数,包括自身的内存分配,或者其他库(象MFC)。一个对象的分配编号是n表示第n个对象被分配,但是它可能并不表示第N个对象通过代码被分配(在大多数情况下它们并不相同)。   
        你可以根据内存分配编号在内存被分配的位置设置断点。先在程序开始部分附近设置一个断点,当你的程序在断点处停止后,你可以通过QuickWatch对话框或者Watch窗口来设置内存分配断点。在Watch窗口中的Name列中输入_crtBreakAlloc,如果你使用的是多线程DLL版本的CRT库的话你必须包含上下文转换   {,,msvcrtd.dll}_crtBreakAlloc。完成后按回车,debugger处理这次调用,并且把返回值显示在Value列中。如果你没有设置内存分配断点的话返回值是-1。在Value列中输入你想设置的分配数,例如18。   
        你在自己感兴趣的内存分配位置设置断点后,你可以继续debugging。细心的运行你的程序在相同的条件下,这样才能保证内存分配的顺序不致发生变化。当程序在特定的内存分配处停下来后,   你可以查看Call   窗口和其他的debugger信息来分析此次内存分配的条件。如果有必要你可以继续运行程序,看一看这个对象有什么变化,或许可以得知为什么内存没有被正确的释放。   
        尽管这个操作非常容易,但是如果你高兴的话也可以在代码中设置断点。在代码中增加一行代码_crtBreakAlloc   =   18;另外也可以通过_CrtSetBreakAlloc(18)来完成设置。   
      

  4.   

    将new换成DEBUG_NEW就行了,能准确定位到内存分配语句上,为了方便,可以采用宏定义:
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
      

  5.   

    对不起,rabo 的方法没太看明白,请问QUICKWATCH对话框和watch窗口是什么东东?
      

  6.   

    VC可以检测一般的内存泄漏:像你程序种明显的用New 分配内存 确没有delete掉
    VC在Debug的时候会显示你LZ的输出结果!但是对于一些资源啊等比较难发现的内存泄漏需要通过别的工具来查找,如BoundsChecker
      

  7.   

    直接用BoundsChecker就行了,非常好用,缺点就是速度有点慢
      

  8.   

    生成dump文件,出错时,还原当时的堆栈
      

  9.   

    #ifdef   _DEBUG 
    #define   new   DEBUG_NEW 
    #endif这个办法不错
      

  10.   

    首先谢谢大家的帮忙,有大家的帮助,感觉真的学到了很多知识!
    to:zyyoung 
    请问你这个办法怎么实现?我是个菜鸟,还请多多指教阿!
      

  11.   

    内存泄漏检测工具--Visual   Leak   Detector   (VLD)   
                可以在http://www.codeproject.com/tools/visualleakdetector.asp   下载到。相比较其它的内存泄露检测工具,它在检测到内存泄漏的同时,还具有如下特点:   
    1、     可以得到内存泄漏点的调用堆栈,如果可以的话,还可以得到其所在文件及行号; 2、     可以得到泄露内存的完整数据; 3、     可以设置内存泄露报告的级别; 4、     它是一个已经打包的lib,使用时无须编译它的源代码。而对于使用者自己的代码,也只需要做很小的改动; 5、     他的源代码使用GNU许可发布,并有详尽的文档及注释。对于想深入了解堆内存管理的读者,是一个不错的选择。                             可见,从使用角度来讲,Visual   Leak   Detector简单易用,对于使用者自己的代码,唯一的修改是#include   Visual   Leak   Detector的头文件后正常运行自己的程序,就可以发现内存问题。从研究的角度来讲,如果深入Visual   Leak   Detector源代码,可以学习到堆内存分配与释放的原理、内存泄漏检测的原理及内存操作的常用技巧等。             使用方法: 
    1.拷贝VLD的头文件(.h文件)到工程的Include目录下。 
    2.拷贝VLD下Lib文件到工程Lib目录下。 
    3.在工程头文件中(比如StdAfx.h)加入#include <vld.h> 。 
    4.Debug版本编译运行即可(release版本不会编译进去)。 
    如果存在内存泄漏,则程序关闭后输出一栏会有详细的提示。 
      

  12.   

    rabo  和 qiujian5628 的方法我试验了一下,都能检测出内存泄露的源码所在,但是我在用rabo说的方法找泄露的内存分配点时,不太会弄,呵呵,相当菜了,多谢各位大虾帮忙,我们上头条了,哈哈
      

  13.   

    我这里找到一个msdn的例子,大家一起学习一下吧!/*****************************************************************
     *      ?000 Microsoft Corporation                   *
     *  CRT_DBG1                                                     *
     *  This simple program illustrates the basic debugging features *
     *  of the C runtime libraries, and the kind of debug output     *
     *  that these features generate.                                *
     *****************************************************************/#include <stdio.h>
    #include <string.h>
    #include <malloc.h>
    #include <crtdbg.h>

    // Disable deprecation warnings.  The unsecure version of strcpy is
    // used intentionally to show off debugging features.
    #pragma warning (disable : 4996)// This routine place comments at the head of a section of debug output
    void OutputHeading( const char * explanation )
    {
       _RPT1( _CRT_WARN, "\n\n%s:\n**************************************\
    ************************************\n", explanation );
    }// The following macros set and clear, respectively, given bits
    // of the C runtime library debug flag, as specified by a bitmask.
    #ifdef   _DEBUG
    #define  SET_CRT_DEBUG_FIELD(a) \
                _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
    #define  CLEAR_CRT_DEBUG_FIELD(a) \
                _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
    #else
    #define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
    #define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
    #endif
    int main( )
    {
       char *p1, *p2;
       _CrtMemState s1, s2, s3;#ifndef _DEBUG
    printf("Skipping this for non-debug mode.\n");
    return 2;
    #endif   // Send all reports to STDOUT
       _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
       _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
       _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
       _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
       _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
       _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );   // Allocate 2 memory blocks and store a string in each
       p1 = malloc( 34 );
       strcpy( p1, "This is the p1 string (34 bytes)." );   p2 = malloc( 34 );
       strcpy( p2, "This is the p2 string (34 bytes)." );
       OutputHeading( 
          "Use _ASSERTE to check that the two strings are identical" );
       _ASSERTE( strcmp( p1, p2 ) == 0 );   OutputHeading( 
          "Use a _RPT macro to report the string contents as a warning" );
       _RPT2( _CRT_WARN, "p1 points to '%s' and \np2 points to '%s'\n", p1, p2 );   OutputHeading( 
          "Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations" );
       _CrtMemDumpAllObjectsSince( NULL );   free( p2 );   OutputHeading( 
          "Having freed p2, dump allocation information about p1 only" );
       _CrtMemDumpAllObjectsSince( NULL );   // Store a memory checkpoint in the s1 memory-state structure
       _CrtMemCheckpoint( &s1 );   // Allocate another block, pointed to by p2
       p2 = malloc( 38 );
       strcpy( p2, "This new p2 string occupies 38 bytes.");   // Store a 2nd memory checkpoint in s2
       _CrtMemCheckpoint( &s2 );   OutputHeading( 
          "Dump the changes that occurred between two memory checkpoints" );
       if ( _CrtMemDifference( &s3, &s1, &s2 ) )
          _CrtMemDumpStatistics( &s3 );   // Free p2 again and store a new memory checkpoint in s2
       free( p2 );
       _CrtMemCheckpoint( &s2 );   OutputHeading( 
          "Now the memory state at the two checkpoints is the same" );
       if ( _CrtMemDifference( &s3, &s1, &s2 ) )
          _CrtMemDumpStatistics( &s3 );   strcpy( p1, "This new p1 string is over 34 bytes" );
       OutputHeading( "Free p1 after overwriting the end of the allocation" );
       free( p1 );   // Set the debug-heap flag so that freed blocks are kept on the
       // linked list, to catch any inadvertent use of freed memory
       SET_CRT_DEBUG_FIELD( _CRTDBG_DELAY_FREE_MEM_DF );   p1 = malloc( 10 );
       free( p1 );
       strcpy( p1, "Oops" );   OutputHeading( "Perform a memory check after corrupting freed memory" );
       _CrtCheckMemory( );   // Use explicit calls to _malloc_dbg to save file name and line number
       // information, and also to allocate Client type blocks for tracking
       p1 = _malloc_dbg( 40, _NORMAL_BLOCK, __FILE__, __LINE__ );
       p2 = _malloc_dbg( 40, _CLIENT_BLOCK, __FILE__, __LINE__ );
       strcpy( p1, "p1 points to a Normal allocation block" );
       strcpy( p2, "p2 points to a Client allocation block" );   // You must use _free_dbg to free a Client block
       OutputHeading( 
          "Using free( ) to free a Client block causes an assertion failure" );
       free( p1 );
       free( p2 );   p1 = malloc( 10 );
       OutputHeading( "Examine outstanding allocations (dump memory leaks)" );
       _CrtDumpMemoryLeaks( );   // Set the debug-heap flag so that memory leaks are reported when
       // the process terminates. Then, exit.
       OutputHeading( "Program exits without freeing a memory block" );
       SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
    }
      

  14.   

    呵呵,对不起,llg84!我主要是不知道加上之后,是一个什么样的效果(比如输出变了),所以没有试,我试验一下奥!
      

  15.   

    直接加的#define new DEBUG_NEW?
      

  16.   

    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    这个,原来就有这行代码,可能是别人加的,我没看到!
      

  17.   

    那你试试#define new DEBUG_NEW,把条件去掉,没道理不显示啊...... 
      

  18.   

    #ifdef _DEBUG
    #undef THIS_FILE
    static char THIS_FILE[]=__FILE__;
    #define new DEBUG_NEW
    #endif
    是这么写的。。