0

У меня есть приложение 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 
+4

Почему вы это делаете, когда эта функция встроена? – sjdowling

ответ

1

Нет необходимости делать это самостоятельно.

В вашем 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 

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

См. here.

+0

Спасибо за подсказку: я полностью неправильно понял описание MSDN, поэтому я попытался реализовать свой собственный класс ... – macilaci123