Visual Studio 2010 — обнаружение утечек памяти в приложении MFC C ++ путем перегрузки новых операторов

У меня есть приложение MFC. Я хотел бы проследить каждое динамическое распределение памяти (в куче), чтобы иметь возможность выяснить источник утечек памяти в этом приложении. Средой разработки является Visual Studio 2010.

Я сделал следующее:

  • Введена директива препроцессора «MEMORY_LEAK_FINDER».
  • Добавлен класс CMemLeakHunter, вы найдете точное содержание
    эти файлы ниже.
  • Идея заключалась в том, чтобы перегружать каждые новые операторы (все
    3 из них: new, new [] и CObject :: new) и использовать их для отслеживания
    место, где была выделена память (файл, строка). В конце
    выполнение я хотел, чтобы привести место утечки памяти в
    вывод с использованием класса ‘CMemoryState’, так что я наконец смог сравнить трассировку распределения с трассировкой сравнения (разности) CMemoryState.

Проблема в том, что приложение компилируется (в режиме отладки VS 2010), но возникают следующие ошибки компоновщика:

Ошибка 4, ошибка LNK2005: «оператор void * __cdecl new [] (unsigned int, char const *, int)» (?? _ U @ YAPAXIPBDH @ Z) уже определен в CMemLeakHunter.obj E: \ Software \ Nafxcwd.lib (afxmem. OBJ)
Ошибка 3, ошибка LNK2005: «оператор void * __cdecl new (unsigned int, char const *, int)» (?? 2 @ YAPAXIPBDH @ Z) уже определен в CMemLeakHunter.obj E: \ Software \ Nafxcwd.lib (afxmem.obj)
Ошибка 5, ошибка LNK2005: «public: static void * __stdcall CObject :: operator new (unsigned int, char const *, int)» (?? 2CObject @@ SGPAXIPBDH @ Z) уже определен в CMemLeakHunter.obj E: \ Software \ Nafxcwd .lib (afxmem.obj)
Ошибка 6 Ошибка 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 записывается следующим образом:

#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 записывается следующим образом:

#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

0

Решение

Не нужно делать это самостоятельно.

В ваш main.cpp входит:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

и в верхней части основного вызова функции:

#ifdef _DEBUG
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

Для каждого файла, где вы хотите обнаружить утечки, поместите это вверху:

#ifdef _DEBUG
#ifndef DBG_NEW
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
#define new DBG_NEW
#endif
#endif  // _DEBUG

Затем любые обнаруженные утечки выводятся на консоль при выходе из приложения.

Увидеть Вот.

1

Другие решения


По вопросам рекламы [email protected]