首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过重载新操作符查找MFC C++应用程序中的内存泄漏

通过重载新操作符查找MFC C++应用程序中的内存泄漏
EN

Stack Overflow用户
提问于 2014-12-04 15:52:52
回答 1查看 584关注 0票数 0

我有一个MFC应用程序。我想跟踪每一个动态内存分配(堆上),以便能够找到该应用程序中内存泄漏的来源。IDE是2010。

我做了以下工作:

  • 引入了一个名为“内存_泄漏_FINDER”的预处理指令。
  • 添加了一个名为“CMemLeakHunter”的类,您可以在下面找到这些文件的确切内容。
  • 其想法是重载每个新操作符(所有3个操作符: new、new[]和CObject:: new ),并使用它们跟踪分配内存的位置(文件、行)。在执行结束时,我希望使用'CMemoryState‘类将内存泄漏的位置带到输出中,这样我最终可以将分配的跟踪与CMemoryState的比较(差异)跟踪进行比较。

问题是,应用程序编译(在VS 2010调试模式中),但是出现了以下链接器错误:

错误4错误LNK2005:"void * __cdecl运算符新无符号int,char const *,int“(??_U@YAPAXIPBDH@Z)已在CMemLeakHunter.obj E:\Software\Nafxcwd.lib(afxmem.obj)错误3错误LNK2005中定义:"void * __cdecl运算符新建(无符号int,char const *,在CMemLeakHunter.obj E:\Software\Nafxcwd.lib(afxmem.obj) error 5 Error LNK2005中已经定义了“(??2@YAPAXIPBDH@Z):"public: Staticvoid* __stdcall CObject::operator new(无符号int,char const *,int)”(?2 CObject@@SGPAXIPBDH@Z)(?2 CObject@@SGPAXIPBDH@Z)已在CMemLeakHunter.obj E:\Software\Nafxcwd.lib(afxmem.obj)错误6 Error LNK1169中定义:找到的一个或多个多重定义符号E:\Software\Module1.exe 1

我搜索并发现,忽略库Nafxcwd.lib可能解决问题。在我的应用程序中,我没有尝试,而是忽略了这个库,这是另一个17000链接器错误(未解决的外部问题)。

其他依赖项是:Nafxcwd.lib;Ws2_32.lib;Version.lib

忽略特定的默认库是:msvcprtd.lib;libcimtd.lib;libcmt.lib

--我不能这么容易地拆分软件,所以我请求帮助:如果我正在使用MFC,并且需要使用上面提到的.lib文件,我如何跟踪我自己的应用程序所做的内存分配?解决办法是什么?请帮助我解决这个问题,以便能够跟踪内存分配,找出泄漏的可能来源。我也是开放的使用另一个MFC内置例程,如果他们能够做到这一点。但是,我自己没有发现任何有用的东西。

头文件CMemLeakHunter.hpp如下所示:

代码语言:javascript
复制
#ifndef _MEM_LEAK_HUNTER_
#define _MEM_LEAK_HUNTER_

#ifdef MEMORY_LEAK_FINDER
#pragma message("Macro MEMORY_LEAK_FINDER is active, overloading new...")

#include "stdafx.h"
#include <map>
using std::map;

#undef new
void* operator new(size_t size, LPCSTR file, int line);
void* operator new[](size_t size, LPCSTR file, int line);
#define new new(__FILE__, __LINE__)

namespace
{
    static const size_t LOG_BUFFER_SIZE = 2;
    static const size_t DEFAULT_BUFFER_LINE_SIZE = 512;
}

class CMemLeakHunter
{
public:
    static CMemLeakHunter& singleton();

    void startMemoryTrace(const char* leakPath, const char* allocPath);
    void endMemoryTrace();

    void addMemory(void* area, size_t size, LPCSTR file, int line);
    void deleteMemory(void* area, LPCSTR file, int line);

private:
    void flushAllocLog();
    void filterTrace();

    map<DWORD, size_t> mMemChunks;
    CString sLogBuffer[LOG_BUFFER_SIZE];
    size_t nLogBufferLines;

    CMemoryState oldMemState;
    CMemoryState newMemState;
    CMemoryState diffMemState;

    CString sMemLeakTracePath;
    CString sMemAllocTracePath;

    static CMutex s_oObjMutex;
};

#endif // MEMORY_LEAK_FINDER

#endif // _MEM_LEAK_HUNTER_

源文件CMemLeakHunter.cpp如下所示:

代码语言:javascript
复制
#include "CMemLeakHunter.hpp"

#ifdef MEMORY_LEAK_FINDER
#pragma message("Memory-Leak finder is activated, building functions for the class...")

#undef new
void* operator new(size_t size, LPCSTR file, int line)
{
    void* pArea = ::operator new(size);
    CMemLeakHunter::singleton().addMemory(pArea, size, file, line);
    return pArea;
}

void* operator new[](size_t size, LPCSTR file, int line)
{
    void* pArea = ::operator new[](size);
    CMemLeakHunter::singleton().addMemory(pArea, size, file, line);
    return pArea;
}

void* PASCAL CObject::operator new(size_t size, LPCSTR file, int line)
{
    void* pArea = CObject::operator new(size);
    CMemLeakHunter::singleton().addMemory(pArea, size, file, line);
    return pArea;
}

CMutex CMemLeakHunter::s_oObjMutex;

CMemLeakHunter& CMemLeakHunter::singleton()
{
    static CMemLeakHunter theSingleObject;
    return theSingleObject;
}

void CMemLeakHunter::startMemoryTrace(const char* leakPath, const char* allocPath)
{
    sMemLeakTracePath = leakPath;
    sMemAllocTracePath = allocPath;

    oldMemState.Checkpoint();

    for(size_t i=0; i<LOG_BUFFER_SIZE; i++)
    {
        sLogBuffer[i] = CString('\0', DEFAULT_BUFFER_LINE_SIZE);
    }
}

void CMemLeakHunter::endMemoryTrace()
{
    newMemState.Checkpoint();
    if(FALSE != diffMemState.Difference(oldMemState, newMemState))
    {
        CFile oDumpFile;
        if(TRUE == oDumpFile.Open(sMemLeakTracePath, CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyWrite))
        {
            CFile* oldContext = afxDump.m_pFile;
            afxDump.m_pFile = &oDumpFile;

            diffMemState.DumpStatistics();
            oDumpFile.Write("\n", 1);
            diffMemState.DumpAllObjectsSince();

            oDumpFile.Close();

            afxDump.m_pFile = oldContext;
        }
        else
        {
            // TODO: log that file cannot be created!!!
        }
    }

    flushAllocLog();
    filterTrace();
}

void CMemLeakHunter::addMemory(void* area, size_t size, LPCSTR file, int line)
{
    CSingleLock oMemHunterTraceLock(&s_oObjMutex, TRUE);

    DWORD nAreaAddr = reinterpret_cast<DWORD>(area);
    mMemChunks[nAreaAddr] = size;

    if(nLogBufferLines >= LOG_BUFFER_SIZE)
    {
        flushAllocLog();
    }

    sLogBuffer[nLogBufferLines++].Format("### Memory allocation: Address 0x%08X, Size: %u, File: '%s', Line: %d\n", nAreaAddr, size, file, line);
}

void CMemLeakHunter::deleteMemory(void* area, LPCSTR file, int line)
{
    CSingleLock oMemHunterTraceLock(&s_oObjMutex, TRUE);

    DWORD nAreaAddr = reinterpret_cast<DWORD>(area);
    mMemChunks.erase(nAreaAddr);

    if(nLogBufferLines >= LOG_BUFFER_SIZE)
    {
        flushAllocLog();
    }

    sLogBuffer[nLogBufferLines++].Format("!!! Memory release: Address 0x%08X, File: '%s', Line: %d\n", nAreaAddr, file, line);
}

void CMemLeakHunter::flushAllocLog()
{
    CStdioFile oAllocFile;
    if(FALSE == PathFileExists(sMemAllocTracePath))
    {
        oAllocFile.Open(sMemAllocTracePath, CFile::modeCreate);
        oAllocFile.Close();
    }

    if(TRUE == oAllocFile.Open(sMemAllocTracePath, CFile::modeReadWrite | CFile::shareDenyWrite))
    {
        oAllocFile.SeekToEnd();
        for(size_t i=0; i<min(nLogBufferLines, LOG_BUFFER_SIZE); i++)
        {
            oAllocFile.WriteString(sLogBuffer[i]);
        }

        oAllocFile.Close();
    }
    else
    {
        // TODO: log that file cannot be accessed!!!
    }

    nLogBufferLines = 0;
}

void CMemLeakHunter::filterTrace()
{
    CStdioFile oAllocFile;
    if(TRUE == oAllocFile.Open(sMemAllocTracePath, CFile::modeRead | CFile::shareDenyWrite))
    {
        CString sFilterTraceFile;
        sFilterTraceFile.Format("filter_%s", sMemAllocTracePath);

        CStdioFile oFilterAllocFile;
        if(TRUE == oFilterAllocFile.Open(sFilterTraceFile, CFile::modeCreate | CFile::modeReadWrite | CFile::shareDenyWrite))
        {
            for (std::map<DWORD, size_t>::iterator it=mMemChunks.begin(); it!=mMemChunks.end(); it++)
            {
                CString addrHex;
                addrHex.Format("0x%08X", it->first);

                CString sLine;
                while(FALSE != oAllocFile.ReadString(sLine))
                {
                    if(sLine.Find(addrHex) > -1)
                    {
                        CString sLineWithNewline;
                        sLineWithNewline.Format("%s\n", sLine);
                        oFilterAllocFile.WriteString(sLineWithNewline);
                    }
                }
            }

            oFilterAllocFile.Close();
        }
        else
        {
            // TODO: log that file cannot be created!!!
        }

        oAllocFile.Close();
    }
    else
    {
        // TODO: log that file cannot be accessed!!!
    }
}

#endif // MEMORY_LEAK_FINDER
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-12-04 16:16:40

不用自己动手。

在您的main.cpp中包括:

代码语言:javascript
复制
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

在主函数调用的顶部:

代码语言:javascript
复制
#ifdef _DEBUG
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

对于要检测泄漏的每个文件,请将其放在顶部:

代码语言:javascript
复制
#ifdef _DEBUG
   #ifndef DBG_NEW
      #define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
      #define new DBG_NEW
   #endif
#endif  // _DEBUG

然后,在应用程序退出时将任何检测到的泄漏输出到控制台。

这里

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27298279

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档