内存泄漏。 FInding行号

时间:2014-10-06 21:34:42

标签: visual-c++ memory-leaks

所以这首先是一个家庭作业项目。我的整个程序正在运行,它是一个处理动态内存分配的中间/高级中介项目。我无法弄清楚如何用正常输出显示行号。我试图在堆栈上查看有关此主题的其他问题,但我似乎无法弄清楚有助于我的理由。有关如何显示行号的任何建议吗?

这是我的"LeakWatcher.cpp"

#ifndef IMWATCHINGYOULEAK
#define IMWATCHINGYOULEAK
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
inline void* operator new(size_t nSize, const char * lpszFileName, int nLine)
{  return ::operator new(nSize, 1, lpszFileName, nLine); }
inline void __cdecl operator delete(void * _P, const char * lpszFileName, int nLine) 
{ ::operator delete(_P, _NORMAL_BLOCK, lpszFileName, nLine); } 
#define DEBUG_NEW new( __FILE__, __LINE__)
#define MALLOC_DBG(x) _malloc_dbg(x, 1, __FILE__, __LINE__);
#define malloc(x) MALLOC_DBG(x)
#define new DEBUG_NEW
#endif // _DEBUG
#endif // #include guard

我的main()

int main()
{
   _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 ); 

   try
   {
      Directory().Run();
   }
   catch ( ... )
   {
      cout << "Uncaught Exception" << endl;
   }

   _CrtDumpMemoryLeaks();

   return 0;
}

2 个答案:

答案 0 :(得分:1)

根据您的代码确实发生的事情就是这个。您说您将所有调试宏放入LeakWatcher.cpp而不是LeakWatcher.h。我怀疑这是你的问题。

使用LeakWatcher.h中当前拥有的所有内容创建LeakWatcher.cpp。您不需要LeakWatcher.cpp,因此您应该可以将其删除。现在在所有#include "LeakWatcher.h"个文件的顶部使用.cpp。所以它看起来像下面这样。

档案 LeakWatcher.h

#ifndef IMWATCHINGYOULEAK 
#define IMWATCHINGYOULEAK
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
inline void* operator new(size_t nSize, const char * lpszFileName, int nLine)
{  return ::operator new(nSize, 1, lpszFileName, nLine); }
inline void __cdecl operator delete(void * _P, const char * lpszFileName, int nLine) 
{ ::operator delete(_P, _NORMAL_BLOCK, lpszFileName, nLine); } 
#define DEBUG_NEW new( __FILE__, __LINE__)
#define MALLOC_DBG(x) _malloc_dbg(x, 1, __FILE__, __LINE__);
#define malloc(x) MALLOC_DBG(x)
#define new DEBUG_NEW
#endif // _DEBUG
#endif // #include guard

然后在 test.cpp 这样的文件中你可以这样做(类似于你的测试代码):

#include "LeakWatcher.h"

int main()
{
    _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);

    new int[40]; // This should be a memory leak

    _CrtDumpMemoryLeaks(); // This should dump with line numbers and file names

    return 0;
}

当然,只有在构建项目的debug版本时,这才有效。

为了获得覆盖这些堆例程的其他一些见解,我发现这个MSDN Article很有价值。

答案 1 :(得分:0)

我认为你问的是跟踪已经分配但未被释放的内存的实际算法。

为了产生诊断输出,跟踪内存分配请求来源的典型方法如下:

  1. 假设您要跟踪来电者请求的n_bytes内存。

  2. 分配n_bytes + sizeof(const char *)+ sizeof(int)。

  3. FILE LINE 存储在已分配内存的第一部分中,并将剩余的已分配内存返回到所谓的已分配内容。

  4. 这样的事情:

    struct hdr {
       const char *file;
       int line;
    };
    
    void *my_allocation_request(const char *file, int line, size_t nbytes)
    {
       struct hdr *p=(struct hdr *)malloc(nbytes+sizeof(hdr));
    
       p->file=file;
       p->line=line;
    
       // Here be dragons
    
       return (void *)(p+1);
    }
    

    (大概,你的new运营商会受到惩罚。)

    类似,当某些东西想要释放内存块时

    void my_deallocation_request(char *p)
    {
        struct hdr *h=reinterpret_cast<hdr *>(p+1);
    
        // Here be dragons
    
        free(h);
    }
    

    在此可以作为最终解决方案之前,您还需要编写更多代码,这些代码将进入“Here be dragons”部分,我想您可能会自己解决这个问题:

    A)取出每个新分配的内存并将其放在某种列表中(龙的第一个位置)。

    B)从某种列表中删除分配的内存(龙的第二个位置)。

    然后,在程序结束时,您可以浏览列表中剩余的任何内容。这将是你泄露的内存,你将拥有文件和分配它的行号。

    请注意,您可能希望手动实现未发布内存块的链接列表。使用一些标准容器可能会导致无限循环,因为容器非常合理地期望能够为自己的内容分配内存,这将循环回你自己的新/删除拦截,这将要求容器分配更多的内存,它将循环回你自己的新/删除拦截等...

    这里可能存在一些关于已分配内存对齐的特定于实现的问题,但这不太可能,而且现在可能会忽略这种分裂。