$ ./helpers/leak-analyze-addr2line memleak_test_so leaks.out Processing "leaks.out"logfor"memleak_test_so" Matching addresses to "memleak_test_so" found 49 leak(s) 100 bytes lost in 1 blocks (one of them allocated at 1444.194222), from following call stack: ??:0 /home/cll/99_temp/memory_leak/leaktracer/memleak_way1/memleak_test.cpp:110 ??:0 ??:? 400 bytes lost in 1 blocks (one of them allocated at 1444.194550), from following call stack: ??:0 /home/cll/99_temp/memory_leak/leaktracer/memleak_way1/memleak_test.cpp:110 ??:0 ??:? 328 bytes lost in 1 blocks (one of them allocated at 1434.190960), from following call stack: /home/cll/99_temp/memory_leak/leaktracer/memleak_way1/memleak_test.cpp:83 ??:0 ??:?
$ ./helpers/leak-analyze-gdb memleak_test_so leaks.out found 49 leak(s) (gdb) Reading symbols from memleak_test_so...done. 16 bytes lost in 1 blocks (one of them allocated at 1434.190803), from following call stack: main + 364 in section .text 0x4025e4 is in main() (memleak_test.cpp:80). 80 new_delete_test *p_new_class_no_free = new new_delete_test; No symbol matches 0x7f05d6333830. _start + 41 in section .text 1 bytes lost in 1 blocks (one of them allocated at 1444.194798), from following call stack: No symbol matches 0x7f05d70f9cee. main + 893 in section .text 0x4027f5 is in main() (memleak_test.cpp:111). 111 leaktracer::MemoryTrace::GetInstance().stopAllMonitoring(); No symbol matches 0x7f05d6333830.
// // LeakTracer // Contribution to original project by Erwin S. Andreasen // site: http://www.andreasen.org/LeakTracer/ // // Added by Michael Gopshtein, 2006 // mgopshtein@gmail.com // // Any comments/suggestions are welcome // #include"MemoryTrace.hpp" #include"LeakTracer_l.hpp" void* (*lt_malloc)(size_t size); void (*lt_free)(void* ptr); void* (*lt_realloc)(void *ptr, size_t size); void* (*lt_calloc)(size_t nmemb, size_t size); void* operatornew(size_t size){ void *p; leaktracer::MemoryTrace::Setup(); p = LT_MALLOC(size); leaktracer::MemoryTrace::GetInstance().registerAllocation(p, size, false); return p; } void* operatornew[] (size_t size) { void *p; leaktracer::MemoryTrace::Setup(); p = LT_MALLOC(size); leaktracer::MemoryTrace::GetInstance().registerAllocation(p, size, true); return p; } voidoperatordelete(void *p){ leaktracer::MemoryTrace::Setup(); leaktracer::MemoryTrace::GetInstance().registerRelease(p, false); LT_FREE(p); } voidoperatordelete[] (void *p) { leaktracer::MemoryTrace::Setup(); leaktracer::MemoryTrace::GetInstance().registerRelease(p, true); LT_FREE(p); } /** -- libc memory operators -- **/ /* malloc * in some malloc implementation, there is a recursive call to malloc * (for instance, in uClibc 0.9.29 malloc-standard ) * we use a InternalMonitoringDisablerThreadUp that use a tls variable to prevent several registration * during the same malloc */ void *malloc(size_t size) { void *p; leaktracer::MemoryTrace::Setup(); leaktracer::MemoryTrace::GetInstance().InternalMonitoringDisablerThreadUp(); p = LT_MALLOC(size); leaktracer::MemoryTrace::GetInstance().InternalMonitoringDisablerThreadDown(); leaktracer::MemoryTrace::GetInstance().registerAllocation(p, size, false); return p; } voidfree(void* ptr) { leaktracer::MemoryTrace::Setup(); leaktracer::MemoryTrace::GetInstance().registerRelease(ptr, false); LT_FREE(ptr); } void* realloc(void *ptr, size_t size) { void *p; leaktracer::MemoryTrace::Setup(); leaktracer::MemoryTrace::GetInstance().InternalMonitoringDisablerThreadUp(); p = LT_REALLOC(ptr, size); leaktracer::MemoryTrace::GetInstance().InternalMonitoringDisablerThreadDown(); if (p != ptr) { if (ptr) leaktracer::MemoryTrace::GetInstance().registerRelease(ptr, false); leaktracer::MemoryTrace::GetInstance().registerAllocation(p, size, false); } else { leaktracer::MemoryTrace::GetInstance().registerReallocation(p, size, false); } return p; } void* calloc(size_t nmemb, size_t size) { void *p; leaktracer::MemoryTrace::Setup(); leaktracer::MemoryTrace::GetInstance().InternalMonitoringDisablerThreadUp(); p = LT_CALLOC(nmemb, size); leaktracer::MemoryTrace::GetInstance().InternalMonitoringDisablerThreadDown(); leaktracer::MemoryTrace::GetInstance().registerAllocation(p, nmemb*size, false); return p; }
内存分配函数记录分配相关的信息
registerAllocation 记录每一次内存分配的相关信息:
1 2 3 4 5 6 7
/** registers new memory allocation, should be called by the * function intercepting "new" calls */ inlinevoidregisterAllocation(void *p, size_t size, bool is_array); /** registers memory reallocation, should be called by the * function intercepting realloc calls */ inlinevoidregisterReallocation(void *p, size_t size, bool is_array);
registerReallocation 记录每一次内存分配的相关信息:
1 2 3
/** registers memory reallocation, should be called by the * function intercepting realloc calls */ inlinevoidregisterReallocation(void *p, size_t size, bool is_array);
// adds all relevant info regarding current allocation to map inlinevoidMemoryTrace::registerAllocation(void *p, size_t size, bool is_array) { allocation_info_t *info = NULL; if (!AllMonitoringIsDisabled() && (__monitoringAllThreads || getThreadOptions().monitoringAllocations) && p != NULL) { MutexLock lock(__allocations_mutex); info = __allocations.insert(p); if (info != NULL) { info->size = size; info->isArray = is_array; storeTimestamp(info->timestamp); } } // we store the stack without locking __allocations_mutex // it should be safe enough // prevent a deadlock between backtrave function who are now using advanced dl_iterate_phdr function // and dl_* function which uses malloc functions if (info != NULL) { storeAllocationStack(info->allocStack); } if (p == NULL) { InternalMonitoringDisablerThreadUp(); // WARNING InternalMonitoringDisablerThreadDown(); } } // adds all relevant info regarding current allocation to map inlinevoidMemoryTrace::registerReallocation(void *p, size_t size, bool is_array) { if (!AllMonitoringIsDisabled() && (__monitoringAllThreads || getThreadOptions().monitoringAllocations) && p != NULL) { MutexLock lock(__allocations_mutex); allocation_info_t *info = __allocations.find(p); if (info != NULL) { info->size = size; info->isArray = is_array; storeAllocationStack(info->allocStack); storeTimestamp(info->timestamp); } } if (p == NULL) { InternalMonitoringDisablerThreadUp(); // WARNING InternalMonitoringDisablerThreadDown(); } }
内存释放函数则销毁内存分配的相关记录
registerReallocation 记录每一次内存释放的相关信息
1 2 3
/** registers new memory allocation, should be called by the * function intercepting "new" calls */ inlinevoidregisterAllocation(void *p, size_t size, bool is_array);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// removes allocation's info from the map inlinevoidMemoryTrace::registerRelease(void *p, bool is_array) { if (!AllMonitoringIsDisabled() && __monitoringReleases && p != NULL) { MutexLock lock(__allocations_mutex); allocation_info_t *info = __allocations.find(p); if (info != NULL) { if (info->isArray != is_array) { InternalMonitoringDisablerThreadUp(); // WARNING InternalMonitoringDisablerThreadDown(); } __allocations.release(p); } } }
遍历所有保存的内存分配记录的信息,并把这些信息保存
writeLeaksToFile 保存内存分配记录信息到文件:
1 2
/** writes report with all memory leaks */ voidwriteLeaksToFile(constchar* reportFileName);