(2.05.19 supplement:
Although the-rdynamic option greatly improves readability, it is still difficult to locate a line of leaked code based on the binary address;
In this case, use objdump-s exefile)
It is easy to detect memory leakage in windows. After all, msdn is powerful and provides many methods. If you are interested, you can view the VLD source code;
A few days ago, I accidentally found from the man document that Linux could hook malloc; so I wrote the following code to detect memory leaks;
The existing program code only needs to be compiled with the linux_vld.o file, and the memory leakage status will be printed upon exit;
For the following files, you can obtain the o file from G ++-C linux_vld.cc;
#ifndef LINUX_VLD_H#define LINUX_VLD_H#include <stdlib.h>#include <malloc.h>#endif
#include <map>#include <vector>#include <string>#include <execinfo.h>#include <cxxabi.h>#include "linux_vld.h"static void *(*old_malloc_hook)(size_t, const void*);static void (*old_free_hook)(void*, const void*);static void *(*old_realloc_hook)(void*, size_t, const void*);static void ReportMemoryLeak(void);static void MyHookInit(void);static void MyHookUnInit(void);static void* MyMallocHook(size_t, const void* );static void* MyReallocHook(void* , size_t , const void* );static void MyFreeHook(void* , const void* );typedef struct{ std::size_t size; std::vector<std::string> stackinfo;} NODE;static std::map<void*, NODE> s_ptrContainer;typedef std::map<void*, NODE>::iterator ITER;namespace{ class HookGuard { private: static HookGuard sm_guard; HookGuard(); public: ~HookGuard(); }; // Hook init in constructor HookGuard HookGuard::sm_guard; HookGuard::HookGuard() { __malloc_initialize_hook = &MyHookInit; atexit(&ReportMemoryLeak); } HookGuard::~HookGuard() { MyHookUnInit(); }} // end namespacestatic void* MyMallocHook(size_t size, const void* caller){ MyHookUnInit(); void* pResult = ::malloc(size); if (NULL != pResult) { NODE node; void* arr[32]; int nFrames= ::backtrace(arr, sizeof(arr)/sizeof(arr[0])); char** strings = ::backtrace_symbols(arr, nFrames); if (NULL != strings) { node.stackinfo.reserve(nFrames); for (int i = 0; i < nFrames; ++ i) { node.stackinfo.push_back(strings[i]); } ::free(strings); } node.size = size; s_ptrContainer[pResult] = node; } MyHookInit(); return pResult;}static void* MyReallocHook(void* ptr, size_t size, const void* caller){ MyHookUnInit(); const bool isFree(ptr != NULL && size == 0); void* pResult = ::realloc(ptr, size); if (NULL != pResult) { NODE node; void* arr[32]; int nFrames= ::backtrace(arr, sizeof(arr)/sizeof(arr[0])); char** strings = ::backtrace_symbols(arr, nFrames); if (NULL != strings) { node.stackinfo.reserve(nFrames); for (int i = 0; i < nFrames; ++ i) { node.stackinfo.push_back(strings[i]); } ::free(strings); } node.size = size; s_ptrContainer[pResult] = node; } else if (isFree) { ITER it = s_ptrContainer.find(ptr); if (it != s_ptrContainer.end()) { s_ptrContainer.erase(ptr); } } MyHookInit(); return pResult;}static void MyFreeHook(void* ptr, const void* caller){ if (NULL == ptr) return ; MyHookUnInit(); ITER it = s_ptrContainer.find(ptr); if (it != s_ptrContainer.end()) { s_ptrContainer.erase(ptr); } ::free(ptr); MyHookInit();}static void MyHookInit(void){ old_malloc_hook = __malloc_hook; old_realloc_hook = __realloc_hook; old_free_hook = __free_hook; __malloc_hook = &MyMallocHook; __realloc_hook = &MyReallocHook; __free_hook = &MyFreeHook;}static void MyHookUnInit(void){ __malloc_hook = old_malloc_hook; __realloc_hook = old_realloc_hook; __free_hook = old_free_hook;}///////////// TESTstatic void ReportMemoryLeak(void){ if (s_ptrContainer.empty()) { printf("DEBUG No Memory leak\n"); return; } ITER it(s_ptrContainer.begin()); while (it != s_ptrContainer.end()) { printf("================================================\n"); printf("DEBUG Memory leak at %p, size =[%lu]bytes\n", it->first, it->second.size); std::vector<std::string>::const_iterator stackiter(it->second.stackinfo.begin()); std::vector<std::string>::const_iterator end(it->second.stackinfo.end()); int frameNo = 0; while (stackiter != end) { std::string mangleName = (*stackiter).c_str(); std::size_t start = mangleName.find('('); std::size_t end = mangleName.find('+', start); if (std::string::npos == start || std::string::npos == end) { printf("Frame[%d]: %s\n", frameNo, (*stackiter).c_str()); } else { ++ start; int status = 0; char* name = abi::__cxa_demangle(mangleName.substr(start, end - start).c_str(), NULL, 0, &status); if (0 == status) { printf("Frame[%d]: %s\n", frameNo, name); ::free(name); } else { printf("Frame[%d]: %s\n", frameNo, (*stackiter).c_str()); } } ++ frameNo; ++ stackiter; } ++ it; }}
The following is a test file. CC. The compilation command is as follows:
G ++-rdynamic file. CC linux_vld.o
#include <stdlib.h> void* TestMalloc() { return ::malloc(12); } void* TestRealloc(void* ptr) { return ::realloc(ptr, 128); } int main(int ac, char* av[]) { void* ptr = TestMalloc(); ::free(ptr); ptr = TestMalloc(); ptr = NULL; ptr = TestRealloc(ptr); }
When the program exits, the output is as follows:
================================================ DEBUG Memory leak at 0x50c010, size =[12]bytes Frame[0]: ./a.out [0x405ee5] Frame[1]: TestMalloc() Frame[2]: ./a.out(main+0x26) [0x4056fa] Frame[3]: /lib64/libc.so.6(__libc_start_main+0xf4) [0x2ab4fc643154] Frame[4]: ./a.out(__gxx_personality_v0+0x69) [0x405619] ================================================ DEBUG Memory leak at 0x50c160, size =[128]bytes Frame[0]: ./a.out [0x405d09] Frame[1]: TestRealloc(void*) Frame[2]: ./a.out(main+0x3b) [0x40570f] Frame[3]: /lib64/libc.so.6(__libc_start_main+0xf4) [0x2ab4fc643154] Frame[4]: ./a.out(__gxx_personality_v0+0x69) [0x405619]