三方应用的内存泄漏问题往往难以定位,传统分析方式效率低下。为提升排查效率,HarmonyOS提供了MallocDispatchTable机制,支持开发者定制内存分配函数的Hook行为,灵活插入自定义监控逻辑,从而实现对内存分配行为的精准追踪与泄漏场景的主动捕获。通过这一能力,开发者可按需定制Hook策略,如记录调用栈、统计分配频次、设置阈值告警等,显著增强内存泄漏问题的定制化分析能力。
注:Hook是计算机编程中的一种钩子技术,它允许开发者拦截、修改或扩展函数的行为。通过使用钩子,开发者可以注入自定义代码,在特定事件发生时修改程序的行为。
本文将介绍以下内容:
MallocDispatchTable简称内存分配表,提供对HarmonyOS libc标准库中的malloc、calloc、realloc、free等内存操作系列函数的Hook能力。此能力可用于跟踪应用的内存分配/释放信息,辅助内存泄漏问题快速定界定位。
注:内存基础知识参考文档:基本概念。
如下图示例,开发者可使用自定义函数替换标准库函数,应用程序调用标准库函数时实际上执行的是自定义的函数。通过MallocDispatchTable里的函数指针,调用标准库函数时可以重定向到自定义的函数。MallocDispatchTable的主要功能在于将标准库函数的实现和自定义函数进行解耦。

开发人员可使用提供的OH_HiDebug_SetMallocDispatchTable()接口设置libc标准库中使用的MallocDispatchTable;使用OH_HiDebug_GetDefaultMallocDispatchTable()接口获取libc中默认的MallocDispatchTable。
开发者观察到程序的匿名内存大小持续上涨,需要记录程序调用标准库的mmap和munmap函数的信息(包括分配内存大小、地址),从而统计使用mmap分配但未被释放(未记录到使用munmap释放对应内存地址)的内存大小。
#include "hidebug/hidebug.h" #include "hidebug/hidebug_type.h"
开发首先需要引用MallocDispatchTable相关的头文件。
static void* MyMmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset)
{
HiDebug_MallocDispatch* original = (HiDebug_MallocDispatch*)OH_HiDebug_GetDefaultMallocDispatchTable();
void* returnAddr = original->mmap(addr, len, prot, flags, fd, offset);
OH_LOG_INFO(LOG_APP, "test MyMmap with len:%{public}d and addr:%{public}p", len, returnAddr);
return returnAddr;
}
static int MyMunmap(void* addr, size_t len)
{
HiDebug_MallocDispatch* original = (HiDebug_MallocDispatch*)OH_HiDebug_GetDefaultMallocDispatchTable();
OH_LOG_INFO(LOG_APP, "test MyMunmap with len:%{public}d and addr:%{public}p", len, addr);
return original->munmap(addr, len);
} 自定义的函数中将内存地址(函数参数addr)以及内存区间大小(函数参数len)通过日志打印。
//Obtain default MallocDispatchTable that can allocate memory directly. HiDebug_MallocDispatch* original = (HiDebug_MallocDispatch*)OH_HiDebug_GetDefaultMallocDispatchTable(); //Create a MallocDispatchTable struct called current. HiDebug_MallocDispatch* current = (HiDebug_MallocDispatch*)original->malloc(sizeof(HiDebug_MallocDispatch)); memset(current, 0, sizeof(HiDebug_MallocDispatch)); //replace function pointers of current, from which self-defined functions can be redirected. current->mmap = MyMmap; current->munmap = MyMunmap;
创建一个HiDebug_MallocDispatch结构体current,通过OH_HiDebug_GetDefaultMallocDispatchTable()分配其占用的堆内存。修改结构体中的函数指针,让其指向之前定义的MyMmap和MyMunmap函数。
OH_HiDebug_SetMallocDispatchTable(current);
将libc标准库中使用的MallocDispatchTable替换成自定义的分配表。
char* mapPtr = nullptr;
const size_t bufferSize = 100; // 100 : the size of memory
mapPtr = (char*)mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (mapPtr == MAP_FAILED) {
printf("mmap failed\n");
return;
}
munmap(mapPtr, bufferSize); 在执行上述基础库mmap函数时,会自动重定向到先前定义的MyMmap函数,完成业务自定义功能。
//release memory of self-defined MallocDispatchTable struct. HiDebug_MallocDispatch* original = (HiDebug_MallocDispatch*)OH_HiDebug_GetDefaultMallocDispatchTable(); original->free(current); //reset MallocDispatchTable strut that libc uses. OH_HiDebug_RestoreMallocDispatchTable();
调用OH_HiDebug_RestoreMallocDispatchTable()接口可以恢复标准库默认的MallocDispatchTable。
add_library(entry SHARED napi_init.cpp test_backtrace.cpp test_malloc_dispatch.cpp) target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libohhidebug.so)
若应用程序设置了自定义的MallocDispatchTable,则与HarmonyOS提供的部分机制存在互斥,请在上述步骤4启用自定义MallocDispatchTable后注意。
具体限制如下: