不改动已存在代码,程序退出时检测内存泄露 .
来源:互联网 发布:淘宝氛围图是什么样的 编辑:程序博客网 时间:2024/06/08 20:06
尽管-rdynamic选项使得可读性大大提高,但仍然不太好根据二进制地址定位到某行泄露代码;
这时使用objdump -S exefile 即可)
在WINDOWS下检测内存泄露比较容易,毕竟MSDN强大,方法多多;有兴趣可以查看VLD源代码;
前几天无意中从MAN文档中查到linux可以给malloc挂钩子;于是写下了如下检测内存泄露的代码;
已存在的程序代码只需要与linux_vld.o文件一起编译链接即可,退出时会打印内存泄露状态;
对于下面文件,g++ -c linux_vld.cc得到o文件即可;
- #ifndef LINUX_VLD_H
- #define LINUX_VLD_H
- #include <stdlib.h>
- #include <malloc.h>
- #endif
#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 namespace
- static 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;
- }
- ///////////// TEST
- static 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;
- }
- }
#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; }}
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);
- }
#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); }
程序退出时输出如下
- ================================================
- 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]
- 不改动已存在代码,程序退出时检测内存泄露
- 不改动已存在代码,程序退出时检测内存泄露 .
- C++程序检测内存泄露
- vs2008 检测内存泄露代码
- ios代码中的内存泄露,内存检测工具leaks 检测不出来
- 如何检测C/C++程序内存泄露
- Linux C程序内存泄露检测
- Linux C程序内存泄露检测
- VC中检测内存泄露的代码
- ffmpeg输入rtmp时存在内存泄露
- 解决程序退出时死锁和内存或资源泄露的问题
- MFC解决程序退出时死锁和内存或资源泄露的问题
- winfrom 程序退出时,进程还是存在....
- 内存泄露检测方法
- 内存泄露检测
- BoundsChecker检测内存泄露
- 内存泄露的检测
- 内存泄露检测相关
- The Best Way to Learn Python-Python学习之路
- Android4.0为all app图标加背景图
- static_cast, dynamic_cast, reinterpret_cast, const_cast区别比较
- IOS开发(88)之动画之视图的移动
- 主要讨论Spring与Hibernate集成中的session问题
- 不改动已存在代码,程序退出时检测内存泄露 .
- 关于一个指针取值的问题
- 网页 折叠菜单代码
- bat实现IP切换
- 软件开发流程
- JVM内存管理
- mysql锁表机制分析
- object c语法速成
- Memcache是什么