每个进程都会执行函数malloc_init_impl初始化内存分配框架。
1)初始化函数
void* malloc_impl_handle = dlopen(DEBUG_SHARED_LIB, RTLD_NOW | RTLD_LOCAL); //加载so库
auto init_func = reinterpret_cast(
dlsym(malloc_impl_handle, "debug_initialize")); // init_func 即debug_initialize,初始化
void* finalize_sym = dlsym(malloc_impl_handle, "debug_finalize");//debug_finalize即 finalize_sym,结束
void* get_leak_info_sym = dlsym(malloc_impl_handle, "debug_get_malloc_leak_info");//get_leak_info_sym 即debug_get_malloc_leak_info,获取泄漏信息
void* free_leak_info_sym = dlsym(malloc_impl_handle, "debug_free_malloc_leak_info");//free_leak_info_sym 即debug_free_malloc_leak_info,释放泄漏信息
2)替换内存分配和释放函数
//调用debug_initialize函数,默认的分配函数是__libc_malloc_default_dispatch,即g_dispatch
if (!init_func(&__libc_malloc_default_dispatch, &gMallocLeakZygoteChild, options)) {
dlclose(malloc_impl_handle);
return;
}
//将MallocDispatch表中的malloc替换成debug_malloc等,这个表即globals->malloc_dispatch
if (!InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "debug")) {
auto finalize_func = reinterpret_cast(finalize_sym);
finalize_func();
dlclose(malloc_impl_handle);
return;
}
1)调用分配函数时
如果使用malloc(4) (leak_debug版,系统会分配4个字节的内存,然后在这个4字节内存的前面分配了一个头。所以整个malloc(4)产生的内存就像这样:
[AllocationEntry | space[4bytes]].
void* debug_malloc(size_t size) {
if (DebugCallsDisabled()) {
return g_dispatch->malloc(size);//默认的分配函数
}
ScopedDisableDebugCalls disable;
void* pointer = internal_malloc(size);//内部调用InitHeader
if (g_debug->config().options & RECORD_ALLOCS) {//记录分配的空间和大小
g_debug->record->AddEntry(new MallocEntry(pointer, size));
}
return pointer;
}
2)调用释放函数时
void debug_free(void* pointer) {
if (DebugCallsDisabled() || pointer == nullptr) {
return g_dispatch->free(pointer);//默认的释放函数
}
ScopedDisableDebugCalls disable;
if (g_debug->config().options & RECORD_ALLOCS) {
g_debug->record->AddEntry(new FreeEntry(pointer));//记录释放空间和大小
}
internal_free(pointer);
}
// =============================================================================
// Exported for use by ddms.
// =============================================================================
// Retrieve native heap information.
//
// "*info" is set to a buffer we allocate
// "*overall_size" is set to the size of the "info" buffer
// "*info_size" is set to the size of a single entry
// "*total_memory" is set to the sum of all allocations we're tracking; does
// not include heap overhead
// "*backtrace_size" is set to the maximum number of entries in the back trace
extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overall_size,
size_t* info_size, size_t* total_memory, size_t* backtrace_size) {
if (g_debug_get_malloc_leak_info_func == nullptr) {
return;
}
g_debug_get_malloc_leak_info_func(info, overall_size, info_size, total_memory, backtrace_size);//调用debug_get_malloc_leak_info
}
void TrackData::GetInfo(uint8_t** info, size_t* overall_size, size_t* info_size,
size_t* total_memory, size_t* backtrace_size) {
ScopedPthreadMutexLocker scoped(&mutex_);
....
*backtrace_size = debug_->config().backtrace_frames;
*info_size = sizeof(size_t) * 2 + sizeof(uintptr_t) * *backtrace_size;
*info = reinterpret_cast(g_dispatch->calloc(*info_size, total_backtrace_allocs_));
if (*info == nullptr) {
return;
}
*overall_size = *info_size * total_backtrace_allocs_;//total_backtrace_allocs_这个变量在分配和释放是都有用到
std::vector list;
GetList(&list);////获取Header的集合,按大小排序
uint8_t* data = *info;
size_t num_allocations = 1;
for (const auto& header : list) {
BacktraceHeader* back_header = debug_->GetAllocBacktrace(header);
if (back_header->num_frames > 0) {
memcpy(data, &header->size, sizeof(size_t));
memcpy(&data[sizeof(size_t)], &num_allocations, sizeof(size_t));
memcpy(&data[2 * sizeof(size_t)], &back_header->frames[0],
back_header->num_frames * sizeof(uintptr_t));
*total_memory += header->real_size();
data += *info_size;
}
}
}
1)header的结构
struct Header {
uint32_t tag;
void* orig_pointer;
size_t size;
size_t usable_size;
size_t real_size() const { return size & ~(1U << 31); }
void set_zygote() { size |= 1U << 31; }
static size_t max_size() { return (1U << 31) - 1; }
} __attribute__((packed));
struct BacktraceHeader {
size_t num_frames;
uintptr_t frames[0];
} __attribute__((packed));
2)header的处理
//分配的时候调用
static void* InitHeader(Header* header, void* orig_pointer, size_t size) {
if (g_debug->config().options & TRACK_ALLOCS) {
g_debug->track->Add(header, backtrace_found);
}
}
//进而调用TrackData中的Add函数
void TrackData::Add(const Header* header, bool backtrace_found) {
pthread_mutex_lock(&mutex_);
if (backtrace_found) {
total_backtrace_allocs_++;
}
headers_.insert(header);
pthread_mutex_unlock(&mutex_);
}
//释放的时候调用
static void internal_free(void* pointer) {
....
if (g_debug->config().options & TRACK_ALLOCS) {
bool backtrace_found = false;
if (g_debug->config().options & BACKTRACE) {
BacktraceHeader* back_header = g_debug->GetAllocBacktrace(header);
backtrace_found = back_header->num_frames > 0;
}
g_debug->track->Remove(header, backtrace_found);
}
....
}
//进而调用TrackData中的Remove函数
void TrackData::Remove(const Header* header, bool backtrace_found) {
pthread_mutex_lock(&mutex_);
headers_.erase(header);
if (backtrace_found) {
total_backtrace_allocs_--;
}
pthread_mutex_unlock(&mutex_);
}
void TrackData::DisplayLeaks() {
std::vector list;
GetList(&list);
size_t track_count = 0;
for (const auto& header : list) {
error_log("+++ %s leaked block of size %zu at %p (leak %zu of %zu)", getprogname(),
header->real_size(), debug_->GetPointer(header), ++track_count, list.size());
if (debug_->config().options & BACKTRACE) {
BacktraceHeader* back_header = debug_->GetAllocBacktrace(header);//为了打印堆栈
// BacktraceHeader (Optional: For the allocation backtrace)
if (back_header->num_frames > 0) {//有堆栈
error_log("Backtrace at time of allocation:");
backtrace_log(&back_header->frames[0], back_header->num_frames);
}
}
g_dispatch->free(header->orig_pointer);
}
}