#内存泄露# #leaktracer# leaktracer使用
https://blog.csdn.net/xiaoting451292510/article/details/105847121
#内存泄露# #leaktracer# leaktracer定制化
https://blog.csdn.net/xiaoting451292510/article/details/105850360
通过上述文章我们可以学习leaktracer使用与leaktracer定制化。在使用的过程 中如果对齐设计原因及实现方式有一定的了解,相信在使用过程中若遇上难道也就能够轻松应对了。
leaktracer主要的设计思路为:
实现一组内存的分配/释放函数,这组函数的函数原型与系统的那一组完全一样,让被trace的library对于内存的分配/释放函数的调用都链接到自己实现的这一组函数中以override掉系统的那组内存/分配释放函数;
自己实现的这组函数中的内存分配函数记录分配相关的信息,包括分配的内存的大小,callstack等,并调用系统本来的内存分配函数去分配内存;
自己实现的这组函数中的内存释放函数则销毁内存分配的相关记录,并使用系统的内存释放函数真正的释放内存;
在trace结束时,遍历所有保存的内存分配记录的信息,并把这些信息保存进文件以供进一步的分析。
LeakTracer实现的用于override系统内存分配/释放函数的那组函数在AllocationHandlers.cpp中定义:
C++
void* operator new(size_t size)
void* operator new[] (size_t size)
void operator delete (void *p)
void operator delete[]
C
void *malloc(size_t size)
void free(void* ptr)
void* realloc(void *ptr, size_t size)
void* calloc(size_t nmemb, size_t size)
//
// 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* operator new(size_t size) {
void *p;
leaktracer::MemoryTrace::Setup();
p = LT_MALLOC(size);
leaktracer::MemoryTrace::GetInstance().registerAllocation(p, size, false);
return p;
}
void* operator new[] (size_t size) {
void *p;
leaktracer::MemoryTrace::Setup();
p = LT_MALLOC(size);
leaktracer::MemoryTrace::GetInstance().registerAllocation(p, size, true);
return p;
}
void operator delete (void *p) {
leaktracer::MemoryTrace::Setup();
leaktracer::MemoryTrace::GetInstance().registerRelease(p, false);
LT_FREE(p);
}
void operator delete[] (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;
}
void free(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;
}
inline void registerAllocation(void *p, size_t size, bool is_array);记录每一次内存分配的相关信息
/** registers new memory allocation, should be called by the
* function intercepting "new" calls */
inline void registerAllocation(void *p, size_t size, bool is_array);
/** registers memory reallocation, should be called by the
* function intercepting realloc calls */
inline void registerReallocation(void *p, size_t size, bool is_array);
inline void registerReallocation(void *p, size_t size, bool is_array);记录每一次内存分配的相关信息,限realloc
/** registers memory reallocation, should be called by the
* function intercepting realloc calls */
inline void registerReallocation(void *p, size_t size, bool is_array);
// adds all relevant info regarding current allocation to map
inline void MemoryTrace::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
inline void MemoryTrace::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();
}
}
inline void registerReallocation(void *p, size_t size, bool is_array);记录每一次内存释放的相关信息
/** registers new memory allocation, should be called by the
* function intercepting "new" calls */
inline void registerAllocation(void *p, size_t size, bool is_array);
// removes allocation's info from the map
inline void MemoryTrace::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);
}
}
}
void writeLeaksToFile(const char* reportFileName);保存内存分配记录信息到文件。
/** writes report with all memory leaks */
void writeLeaksToFile(const char* reportFileName);
// writes all memory leaks to given stream
void MemoryTrace::writeLeaksToFile(const char* reportFilename)
{
MutexLock lock(__allocations_mutex);
InternalMonitoringDisablerThreadUp();
std::ofstream oleaks;
if (!isFolderExist(reportFilename)) {
createDirectory(reportFilename);
}
if (__allocations.empty()) {
return; //no memory leak, not need to create leak file
}
oleaks.open(reportFilename, std::ios_base::out);
if (oleaks.is_open())
{
writeLeaksPrivate(oleaks);
oleaks.close();
}
else
{
std::cerr << "Failed to write to \"" << reportFilename << "\"\n";
}
InternalMonitoringDisablerThreadDown();
}
遍历自定义MapMemoryInfo 中所有元素。
// writes all memory leaks to given stream
void MemoryTrace::writeLeaksPrivate(std::ostream &out)
{
struct timespec mono, utc, diff;
allocation_info_t *info;
void *p;
double d;
const int precision = 6;
int maxsecwidth;
clock_gettime(CLOCK_REALTIME, &utc);
clock_gettime(CLOCK_MONOTONIC, &mono);
if (utc.tv_nsec > mono.tv_nsec) {
diff.tv_nsec = utc.tv_nsec - mono.tv_nsec;
diff.tv_sec = utc.tv_sec - mono.tv_sec;
} else {
diff.tv_nsec = 1000000000 - (mono.tv_nsec - utc.tv_nsec);
diff.tv_sec = utc.tv_sec - mono.tv_sec -1;
}
maxsecwidth = 0;
while(mono.tv_sec > 0) {
mono.tv_sec = mono.tv_sec/10;
maxsecwidth++;
}
if (maxsecwidth == 0) maxsecwidth=1;
out << "# LeakTracer report";
d = diff.tv_sec + (((double)diff.tv_nsec)/1000000000);
out << " diff_utc_mono=" << std::fixed << std::left << std::setprecision(precision) << d ;
out << "\n";
__allocations.beginIteration();
while (__allocations.getNextPair(&info, &p)) {
d = info->timestamp.tv_sec + (((double)info->timestamp.tv_nsec)/1000000000);
out << "leak, ";
out << "time=" << std::fixed << std::right << std::setprecision(precision) << std::setfill('0') << std::setw(maxsecwidth+1+precision) << d << ", "; // setw(16) ?
out << "stack=";
#ifdef BACKTRACE_SYMBOLS_USED
unsigned int i_depth = 0;
for (i_depth = 0; i_depth < ALLOCATION_STACK_DEPTH; i_depth++) {
if (info->allocStack[i_depth] == NULL) break;
if (i_depth > 0) out << ' ';
out << info->allocStack[i_depth];
}
out << '\n';
char **trace_symbols = (char **)backtrace_symbols (info->allocStack, i_depth);
if (NULL != trace_symbols) {
size_t name_size = 64;
char *name = (char*)malloc(name_size);
for (unsigned int j = 0; j < i_depth; j++) {
char *begin_name = 0;
char *begin_offset = 0;
char *end_offset = 0;
for (char *p = trace_symbols[j]; *p; ++p) {
if (*p == '(') {
begin_name = p;
} else if (*p == '+' && begin_name) {
begin_offset = p;
} else if (*p == ')' && begin_offset) {
end_offset = p;
break;
}
}
if (begin_name && begin_offset && end_offset ) {
*begin_name++ = '\0';
*begin_offset++ = '\0';
*end_offset = '\0';
int status = -4;
char *ret = abi::__cxa_demangle(begin_name, name, &name_size, &status);
if (0 == status) {
name = ret;
out << trace_symbols[j] << ":" << name << "+" << begin_offset;
} else {
out << trace_symbols[j] << ":" << begin_name << "()+" << begin_offset;
}
} else {
out << trace_symbols[j];
}
out << '\n';
}
free(trace_symbols);
}
#else
for (unsigned int i = 0; i < ALLOCATION_STACK_DEPTH; i++) {
if (info->allocStack[i] == NULL) break;
if (i > 0) out << ' ';
out << info->allocStack[i];
}
out << ", ";
#endif
out << "size=" << info->size << ", ";
out << "data=";
const char *data = reinterpret_cast<const char *>(p);
for (unsigned int i = 0; i < PRINTED_DATA_BUFFER_SIZE && i < info->size; i++)
out << (isprint(data[i]) ? data[i] : '.');
out << '\n';
}
}
整体来看LeakTracer的设计与实现都并不复杂,因而能够trace的memory issue也就有限。比如,LeakTracer就无法trace多次释放等问题。但我们可以通过源码编写更强大的内存相关的trace工具。