2012-08-08 43 views
3

我想用C來寫內存跟蹤++中進入無限循環。但它正在循環並且一次又一次地呼叫new。以下是我的代碼。內存跟蹤++超載<code>new</code>和<code>delete</code>操作向量初始化

#ifndef MEMORY_TRACKER_H_ 
#define MEMORY_TRACKER_H_ 

#pragma warning(disable : 4290) 
#pragma comment(lib, "Dbghelp.lib") 

#include <Windows.h> 
#include <malloc.h> 
#include <map> 
#include <iostream> 
#include <DbgHelp.h> 
#include <sstream> 
#include <vector> 


static const int MAX_TRACES  = 62; 
static const int MAX_LENGTH  = 256; 
static const int BUFFER_LENGTH = (sizeof(SYMBOL_INFO) + MAX_LENGTH * sizeof(wchar_t) + sizeof(ULONG64) - 1)/sizeof(ULONG64); 
static bool SYSTEM_INITIALIZED = false; 

typedef struct record_t { 
    std::string symbol; 
    std::string address; 
    std::string filename; 
    std::string linenumber; 
} record; 

typedef std::vector<record>    record_vec_t; 
typedef std::pair<size_t, record_vec_t> record_entry_t; 
typedef std::map<size_t, record_entry_t> memory_record_t; 

memory_record_t gMemoryRecord; 

static record_vec_t GetCallStackDetails(const void* const* trace, int count) { 
    record_vec_t callStackVector; 

    for (int i = 0; i < count; ++i) { 
     ULONG64 buffer[BUFFER_LENGTH]; 
     DWORD_PTR frame   = reinterpret_cast<DWORD_PTR>(trace[i]); 
     DWORD64 sym_displacement = 0; 
     PSYMBOL_INFO symbol  = reinterpret_cast<PSYMBOL_INFO>(&buffer[0]); 
     symbol->SizeOfStruct  = sizeof(SYMBOL_INFO); 
     symbol->MaxNameLen  = MAX_LENGTH; 
     BOOL has_symbol   = SymFromAddr(GetCurrentProcess(), frame, &sym_displacement, symbol); 
     DWORD line_displacement = 0; 
     IMAGEHLP_LINE64 line  = {}; 
     line.SizeOfStruct   = sizeof(IMAGEHLP_LINE64); 
     BOOL has_line    = SymGetLineFromAddr64(GetCurrentProcess(), frame, &line_displacement, &line); 

     record curr_rec; 
     curr_rec.symbol = "(No Symbol)"; 

     std::stringstream formatter;   
     if (has_symbol) { 
      curr_rec.symbol = symbol->Name; 
      formatter.clear(); 
      formatter << " [0x" << trace[i] << "+" << sym_displacement << "]";  
      curr_rec.address = formatter.str(); 
     } else { 
      formatter.clear(); 
      formatter << " [0x" << trace[i] << "]"; 
      curr_rec.address = formatter.str(); 
     } 
     if (has_line) { 
      formatter.clear(); 
      formatter << line.FileName; 
      curr_rec.filename = formatter.str(); 

      formatter.clear(); 
      formatter << line.LineNumber; 
      curr_rec.filename = formatter.str(); 
     } 
     callStackVector.push_back(curr_rec); 
    } 
    return callStackVector; 
} 

static void addRecord(void *ptr, size_t size) { 
    if (SYSTEM_INITIALIZED == false) { 
     SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES); 
     if (SymInitialize(GetCurrentProcess(), NULL, TRUE)) { 
      SYSTEM_INITIALIZED = true; 
     } else { 
      SYSTEM_INITIALIZED = false; 
      return; 
     } 
    } 
    void* trace[MAX_TRACES]; 

    int count   = CaptureStackBackTrace(0, MAX_TRACES , trace, NULL); 
    record_vec_t record = GetCallStackDetails(trace, count); 
    record_entry_t entry = std::make_pair(size, record); 

    gMemoryRecord.insert(std::make_pair((size_t)ptr, entry)); 
} 

static void deleteRecord(void *ptr) { 
    memory_record_t::iterator itr = gMemoryRecord.find((size_t)ptr); 
    if (itr != gMemoryRecord.end()) { 
     gMemoryRecord.erase(itr); 
    } 
} 

void dumpUnfreedMemory() { 
    for (memory_record_t::iterator itr = gMemoryRecord.begin(); itr != gMemoryRecord.end(); ++itr) { 
    } 
} 

// Overloading new operator 
void* operator new (size_t size) throw (std::bad_alloc) { 
    std::cout << " Overloaded new is called " << std::endl; 
    void *ptr = (void *)malloc(size); 
    addRecord(ptr, size); 

    return ptr; 
} 

// Overloading delete Operator 
void operator delete (void* ptr) throw() { 
    std::cout << " Overloaded delete is called " << std::endl; 
    deleteRecord(ptr); 
    free (ptr); 
} 

#endif 

下面是測試文件

#include "MemoryTracker.h" 
int main (int argc, char **argv) { 
    int *ptr = new int; 
    return 0; 
} 

它進入環上的GetCallStackDetails電話,平臺是windows

回答

4

你超載了全球operator new,並std::vector<record>使用默認分配器,它調用operator new來分配內存。然後調用你的GetCallStack,它分配一個新的矢量....

一個解決方案是在你的向量中使用一個自定義的分配器,它從一個單獨的內存池中抽取,以便它不調用你的GetCallStack。

+0

謝謝,我如何指定自定義分配器,使其調用的std ::新的運營商 – Avinash 2012-08-08 18:51:46

+1

的問題是,你剛剛更換'運營商new',所以這是一個它會調用。就像'std :: map','std :: string',還有'std :: stringstream'一樣。實施低級功能時,您不能使用高級功能。考慮一下你是否真的需要實現全局運算符,或者如果你可以爲你想跟蹤的類創建'operator new'。 – 2012-08-08 19:31:17

+0

感謝戴夫S,我理解了這個問題,並刪除了我的代碼中的整個使用STL。 這裏是鏈接[在Windows C++應用程序查找內存泄漏](http://avdongre.wordpress.com/2012/08/09/finding-memory-leak-in-c-application-on-windows/) – Avinash 2012-08-09 10:51:36