У меня есть приложение MFC. Я хотел бы отслеживать все распределения динамической памяти (в куче), чтобы узнать источник утечек памяти в этом приложении. IDE является Visual Studio 2010.Поиск утечек памяти в приложении MFC C++ при перегрузке новых операторов
я сделал следующее:
- Введенный директиву препроцессора под названием 'MEMORY_LEAK_FINDER'.
- Добавлен класс под названием «CMemLeakHunter», вы найдете точный контент этих файлов ниже.
- Идея состояла в том, чтобы перегрузить все новые операторы (все 3 из них: новые, новые [] и CObject :: new) и использовать их для отслеживания местоположения , где выделена память (файл, строка). В конце выполнения я хотел принести местоположение утечек памяти на вывод с использованием класса «CMemoryState», поэтому я мог бы, наконец, сравнить трассировку распределения с трассировкой сравнения (разности) CMemoryState.
Проблема заключается в том, что компилирует приложения (в VS 2010 режиме отладки), но следующие ошибки компоновщика имеют место:
Ошибка 4 Ошибка LNK2005: «пустота * __cdecl оператор новый [] (unsigned int, char const *, int) "(?? _ U @ YAPAXIPBDH @ Z), уже определенный в CMemLeakHunter.obj E: \ Software \ Nafxcwd.lib (afxmem.obj) Ошибка 3 ошибки LNK2005:" void * __cdecl operator 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.каст записывается как не следует:
#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
Почему вы это делаете, когда эта функция встроена? – sjdowling