zoukankan      html  css  js  c++  java
  • 关于THIS_FILE

    VC++中本身就有内存泄漏检查的机制,可以在向导生成的支持MFC的工程中看到如下代码:
      #ifdef _DEBUG
      #define new DEBUG_NEW
      #undef THIS_FILE
      static char THIS_FILE[] = __FILE__;
      #endif

    先具体解释一下:

    #ifdef _DEBUG //如果有定义_DEBUG 
    #define new DEBUG_NEW //将new宏定义成DEBUG_NEW, 
    那么则是代码中有new的都换成DEBUG_NEW。 
    #undef THIS_FILE//取消THIS_FILE的宏定义 
    static char THIS_FILE[] = __FILE__;//将THIS_FILE 
    定义成一个数组,该数组用static声名,则只能在该文件内访问。__FILE__是gcc定义的一个扩展宏,代表的该文件的文件名。 
    #endif//这个不用说了吧 

    MFC Library中的解释
    THIS_FILESee Also
    MFC Macros and Globals | ASSERT | VERIFYExpands to the name of the file that is being compiled.
    THIS_FILE
    Remarks
    The information is used by the ASSERT and VERIFY macros. The Application Wizard and code wizards place the macro in source code files they create.
    Example
    #ifdef _DEBUG
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    // __FILE__ is one of the six predefined ANSI C macros that the 
    // compiler recognizes.
    有了这样的定义,在编译DEBUG版时,出现在这个cpp文件中的所有new都被替换成DEBUG_NEW了。那么DEBUG_NEW是什么呢?DEBUG_NEW也是一个宏,以下摘自afx.h,1632行
     
    #define DEBUG_NEW new(THIS_FILE, __LINE__)
     
    所以如果有这样一行代码:
     
    char* p = new char[200];
     
    经过宏替换就变成了:
     
    char* p = new( THIS_FILE, __LINE__)char[200];
     
    根据C++的标准,对于以上的new的使用方法,编译器会去找这样定义的operator new:
     
    void* operator new(size_t, LPCSTR, int)
     
    我们在afxmem.cpp 63行找到了一个这样的operator new 的实现
     
    void* AFX_CDECL operator new(size_t nSize, LPCSTR lpszFileName, int nLine)
    {
           return ::operator new(nSize, _NORMAL_BLOCK, lpszFileName, nLine);
    }
     
    void* __cdecl operator new(size_t nSize, int nType, LPCSTR lpszFileName, int nLine)
    {
           …
                  pResult = _malloc_dbg(nSize, nType, lpszFileName, nLine);
                  if (pResult != NULL)
                         return pResult;
           …
    }
     
    第二个operator new函数比较长,为了简单期间,我只摘录了部分。很显然最后的内存分配还是通过_malloc_dbg函数实现的,这个函数属于MS C-Runtime Library 的Debug Function。这个函数不但要求传入内存的大小,另外还有文件名和行号两个参数。文件名和行号就是用来记录此次分配是由哪一段代码造成的。如果这块内存在程序结束之前没有被释放,那么这些信息就会输出到Debug窗口里。
     
    这里顺便提一下THIS_FILE,__FILE和__LINE__。__FILE__和__LINE__都是编译器定义的宏。当碰到__FILE__时,编译器会把__FILE__替换成一个字符串,这个字符串就是当前在编译的文件的路径名。当碰到__LINE__时,编译器会把__LINE__替换成一个数字,这个数字就是当前这行代码的行号。在DEBUG_NEW的定义中没有直接使用__FILE__,而是用了THIS_FILE,其目的是为了减小目标文件的大小。假设在某个cpp文件中有100处使用了new,如果直接使用__FILE__,那编译器会产生100个常量字符串,这100个字符串都是这个cpp文件的路径名,显然十分冗余。如果使用THIS_FILE,编译器只会产生一个常量字符串,那100处new的调用使用的都是指向常量字符串的指针。
     
    再次观察一下由MFC Application Wizard生成的项目,我们会发现在cpp文件中只对new做了映射,如果你在程序中直接使用malloc函数分配内存,调用malloc的文件名和行号是不会被记录下来的。如果这块内存发生了泄漏,MS C-Runtime Library仍然能检测到,但是当输出这块内存块的信息,不会包含分配它的的文件名和行号。
     
    要在非MFC程序中打开内存泄漏的检测功能非常容易,你只要在程序的入口处加入以下几行代码:
     
    int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
    tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
    _CrtSetDbgFlag( tmpFlag );
     
    这样,在程序结束的时候,也就是winmain,main或dllmain函数返回之后,如果还有内存块没有释放,它们的信息会被打印到Debug窗口里。
     
    如果你试着创建了一个非MFC应用程序,而且在程序的入口处加入了以上代码,并且故意在程序中不释放某些内存块,你会在Debug窗口里看到以下的信息:
     
    {47} normal block at 0x00C91C90, 200 bytes long.
     Data: <                > 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
     
    内存泄漏的确检测到了,但是和上面MFC程序的例子相比,缺少了文件名和行号。对于一个比较大的程序,没有这些信息,解决问题将变得十分困难。
     
    为了能够知道泄漏的内存块是在哪里分配的,你需要实现类似MFC的映射功能,把new,maolloc等函数映射到_malloc_dbg函数上。这里我不再赘述,你可以参考MFC的源代码。
    由于Debug Function实现在MS C-RuntimeLibrary中,所以它只能检测到堆内存的泄漏,而且只限于malloc,realloc或strdup等分配的内存,而那些系统资源,比如HANDLE,GDI Object,或是不通过C-Runtime Library分配的内存,比如VARIANT,BSTR的泄漏,它是无法检测到的,这是这种检测法的一个重大的局限性。另外,为了能记录内存块是在哪里分配的,源代码必须相应的配合,这在调试一些老的程序非常麻烦,毕竟修改源代码不是一件省心的事,这是这种检测法的另一个局限性。
  • 相关阅读:
    107. Binary Tree Level Order Traversal II
    103. Binary Tree Zigzag Level Order Traversal
    102. Binary Tree Level Order Traversal
    690. Employee Importance
    1723. Find Minimum Time to Finish All Jobs
    LeetCode 329 矩阵中最长增长路径
    7.2 物理内存管理
    LeetCode 面试题 特定深度节点链表
    LeetCode 100 相同的树
    npm安装包命令详解,dependencies与devDependencies实际区别
  • 原文地址:https://www.cnblogs.com/xly1208/p/3611671.html
Copyright © 2011-2022 走看看