分类

  • 软件天地

  • 使用VC++和CRT库定位和排除内存泄漏‖
      动态分配、回收内存是
    我不知道是谁?那位知道?
    正确,在内存处理出错的地
    泄漏-没有把前边分配的内
    大块内存,或者渐增式的泄
    耗尽错误。最坏的是,一个
    ,留给用户的是不能知道错
    问题的先兆。幸运的是VC++
    文描述如何使用这些工具有
    C/C++编程语言一个最强的特点
    ) 指出,最强的同时也是最弱
    方通常就是BUGS产生的地方。一
    存成功释放,一个小的内存泄漏
    漏内存可能引起的现象是:先是
    内存泄漏程序可能用完了如此多
    误到底来自哪里。另外,一个看
    DEBUGER和CRT库提供了一组有效
    效和系统的排除内存泄漏。
    ,但是中国哲学家孙(Sun Tzu,
    的。饩浠岸訡/C++应用来说非常
    个最敏感和难检测的BUG就是内存
    可能不需要太注意,但是程序泄漏
    性能低下,再就是引起复杂的内存
    的内存以至于引起其他的程序出错
    上去无害的内存泄漏可能是另一个
    的检测和定位内存泄漏的工具。本


      启动内存泄漏检测:

      主要的检测工具是DEBU
    含以下几个语句:
    GER和CRT堆除错函数。要使除错

    函数生效,必须要在你的程序中包


      #define _CRTDBG_MAP_ALLOC                            
      #include "stdlib.h"                                        
      #include "crtdbg.h"                                        

      并且这些#include 语
    的函数工作不正常。包含cr
    和 _free_dbg)来替换他们
    效,Relese版本中还是使用
    句必须按上边给出的顺序使用。
    tdbg.h的作用是用malloc和free
    ,他们能跟倌诖娣峙浜突厥铡?br>普通的malloc和free函数。
    如果你改变了顺序,可能导致使用
    函数的debug版本(_malloc_dbg
    这个替换仅仅是在debug状态下生

      上面的#define语句使用crt堆函数相
    必需的,但是没有他,你可能会失去一些
    应的debug版本来替换正常的堆函数。这个语句不是
    有用的内存泄漏信息。

      你一旦在你的程序中增加了以上的语
    _CrtDumpMemoryLeaks();函数来输出内存
    句,你可以通过在程序中增加
    泄漏信息。

      当你在debuger下运行
    口的Debug标签项里。内存
    你的程序时,_CrtDumpMemoryLe
    泄漏信息举例如下:
    aks 显示内存泄漏信息在OutPut窗


      Detected memory leaks!                                  
      Dumping objects ->

      C:PROGRAM FILESVISUAL STUDIOM
    yProjectsleaktestleaktest.cpp(20) : {18}

      normal block at 0x00
    780E80, 64 bytes long.
      Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD

      Object dump complete.                                    
      如果你没有使用 #defi
    ne _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_ALLO
    信息。在没有定义_CRTDBG_MAP_ALLOC 的
    C 被定义后_CrtDumpMemoryLeaks给了你很多有用的
    情况下,显示信息包含:
      1.内存分配的编号(大括弧中的数字);                                        
      2.内存快的类型(普通型、客户端型、CRT型);                              
      3.16进制表示的内存位置;                                                  
      4.内存快的大小;                                                            
      5.前16bytes的内容。                                                  

      如果定义了_CRTDBG_MAP_ALLOC ,输
    定位信息。文件名后圆括弧中的数字是行
    出信息还包含当前泄漏内存是在那个文件中被分配的
    数。如果你双击这行信息,

      C:PROGRAM FILESVIS
    UAL STUDIOMyProjectsleakte
    stleaktest.cpp(20) : {18}

      normal block at 0x00
    780E80, 64 bytes long.

      光标就会跳转到原文件中分配这个内
    的效果。
    存的行前。选择Output中的题是行,按F4能达到同样


      使用Using _CrtSetDbgFlag:

      如果你的程序的退出点
    如果你的程序有多个退出点
    _CrtDumpMemoryLeaks,你
    只有一个的话,调用_CrtDumpMe
    话会是什么样一个情况?如果不
    可以在程序的开始包含以下调用
    moryLeaks将是非常容易。但是,
    想在每个退出点都调用


      _CrtSetDbgFlag( _CRT
    DBG_ALLOC_MEM_DF | _CRTDBG_L
    EAK_CHECK_DF);
      这个语句会在你的程序结束时自动调
    那样设置_CRTDBG_ALLOC_MEM_DF 和 _CRT
    用_CrtDumpMemoryLeaks,但是你必须象前边提到的
    DBG_LEAK_CHECK_DF这两个标志位。

      介绍一下内存块的类型:

      就象前面指出的,一个
    型。在实际程序中,普通型
    内存泄漏信息指出每个内存泄漏
    和客户端型式最常见的类型。
    块的类型为普通、客户端或者CRT


      普通型内存块是你的程序平常分配的内存类型。                                    

      客户端型内存块是MFC程序给需要析
    型或客户端型中合适的一种作为将要被创
    构的对象分配的内存块。MFC的new操作可以选择普通
    建的对象的内存块类型。

      CRT内存块是CRT库为自
    些块,所以在内存泄漏报告
    己使用而分配的内存块。CRT在
    中这种类型并不常见,除非发生
    处理自己的释放内存操作时使用这
    严重异常(例如:CRT库出错)。

      还有两种类型你在内存泄漏信息中看不到:                                        

      自由块,它是已经被释放的内存块;                                              
      忽略块,它是已经被特殊标示的内存块。                                          

      设置CRT报告的格式:

      在默认情况下,_CrtDu
    使用_CrtSetReportMode让
    出信息到其他的地方,在这
    _CRTDBG_MODE_DEBUG );语
    mpMemoryLeaks输出的内存泄漏
    这些输出信息输出到其他地方。
    种情况下,你可以使用_CrtSetR
    句使输出信息重新定位到Output
    信息就象前边描述的那样。你可以
    如果你使用一个库,它可能要使输
    eportMode( _CRT_ERROR,
    窗口。

      根据内存分配编号设置断点:

      内存泄漏报告中的文件名和行数告诉
    能找到问题所在。在一个运行的程序中一
    只发生在其中的某次操作中。为了确认问
    道发生泄漏的条件。内存分配编号使得解
    后的大括弧凇@纾谏厦娴氖涑鲋小?br>泄漏发生在第18次分配操作中。
    你内存泄漏的位置,但是知道内存泄漏位置不是总是
    个内存分配操作可能被调用多次,但是内存泄漏可能
    题所在,你除了知道泄漏的位置之外,你还必须要知
    决这个问题成为可能。这个数字就在文件名、行数之
    18”就是内存分配编号,它的意思是你程序中的内存


      CRT库对正在运行程序
    (象MFC)。一个对象的分
    通过代码被分配(在大多数
    中所有的内存块分配进行计数,
    配编号是n表示第n个对象被分配
    情况下它们并不相同)。
    包括自身的内存分配,或者其他库
    ,但是它可能并不表示第N个对象


      你可以根据内存分配编号在内存被分
    断点,当你的程序在断点处停止后,你可
    分配断点。在Watch窗口中的Name列中输
    的CRT库的话你必须包含上挛淖?{,,m
    debugger处理这次调用,并且把返回值显
    返回值是-1。在value列中输入你想设置
    配的位置设置断点。先在程序开始部分附近设置一个
    以通过QuickWatch对话框或者Watch窗口来设置内存
    入_crtBreakAlloc,如果你使用的是多线程DLL版本
    svcrtd.dll}_crtBreakAlloc。完成后按回车,
    示在value列中。如果你没有设置内存分配断点的话
    的分配数,例如18。

      你在自己感兴趣的内存分配位置设置
    序在相同的条件下,这样才能保证内存分
    停下来后, 你可以查看Call 窗口和其他
    必要你可以继续运行程序,看一看这个对
    的释放。
    断点后,你可以继续debugging。细心的运行你的程
    配的顺序不致发生变化。当程序在特定的内存分配处
    的debugger信息来分析此次内存分配的条件。如果有
    象有什么变化,或许可以得知为什么内存没有被正确


      尽管这个操作非常容易
    行代码_crtBreakAlloc = 1
    ,但是如果你高兴的话也可以在
    8;另外也可以通过_CrtSetBreak
    代码中设置断点。在代码中增加一
    Alloc(18)来完成设置。

      比较内存状态

      另一个定位内存泄漏的
    个结构体类型 _CrtMemStat
    方法是在重要位置捕捉应用程序
    e,使用它你可以保存内存状态
    的“内存快照”。CRT库提供了一
    的快照(当前状态)。

      _CrtMemState s1, s2, s3;                              

      为了得到一个快照,可以把一个_Crt
    个函数可以把当前的内存状态填充在结构
    MemState 结构体传给_CrtMemCheckpoint 函数,这
    体中:

      _CrtMemCheckpoint( &s1 );                            

      你可以通过把结构体_CrtMemState
    内容。
    传给_CrtMemDumpStatistics函数来输出结构体中的

      _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.                  

      为了得知一段代码中是
    ,然后调用_CrtMemDiffere
    否有内存泄漏,你可以在这段代
    nce函数来比较两个状态:
    码的开始和完成处分别拍一个快照


      _CrtMemCheckpoint( &s1 );                            
      // memory allocations take place here    
      _CrtMemCheckpoint( &s2 );                            


      if ( _CrtMemDifferen
    ce( &s3, &s1, &s2) )
      _CrtMemDumpStatistics( &s3 );                    

      就像名字中暗示的那样
    一个参数)。把 _CrtMemCh
    较结果,这也是一种检测内
    rtMemCheckpoint把程序分
    检查内存泄漏。
    ,_CrtMemDifference比较两个
    eckpoint 放在程序的开始和结
    存泄漏的方法。如果发现内存泄
    成两半分别使用上述方法来检测

    内存状态,并且产生一个结果(第
    尾,调用_CrtMemDifference 来比
    漏,你可以使用_C
    内存泄漏,这样就是使用二分法来


    上一页 下一页




    map