C语言中如何实现函数内存分配追踪?释放时如何获取内存大小?
如何在内存追踪中获取free()释放的内存大小
要实现完整的内存追踪(统计各调用方的内存分配/释放情况),解决free()无法返回内存大小的问题,常用以下几种实用方案:
1. 包装malloc,额外嵌入内存大小信息
自己实现malloc和free的包装函数,在分配内存时额外预留空间存储申请的大小,释放时取出该大小再做统计:
- 分配时,多申请一段
size_t大小的空间,把用户请求的内存大小存在这段空间的起始位置,返回给用户的指针跳过这段存储区; - 释放时,将用户传入的指针回退到存储大小的起始地址,取出大小后再调用真正的free释放整个内存块。
示例代码:
#include <stdlib.h> #include <stddef.h> // 自定义malloc,嵌入大小信息 void* my_malloc(size_t size) { void* raw_ptr = malloc(size + sizeof(size_t)); if (!raw_ptr) return NULL; // 存储申请的大小 *(size_t*)raw_ptr = size; // 返回给用户的指针跳过大小存储区 return (char*)raw_ptr + sizeof(size_t); } // 自定义free,取出大小并更新统计 void my_free(void* ptr) { if (!ptr) return; // 回退到存储大小的地址 void* raw_ptr = (char*)ptr - sizeof(size_t); size_t freed_size = *(size_t*)raw_ptr; // 这里根据freed_size更新你的内存统计哈希表(比如对应调用方的内存占用减少) free(raw_ptr); } // 用宏替换系统malloc/free,实现全局拦截 #define malloc my_malloc #define free my_free
注意:宏替换要确保在所有包含stdlib.h的代码之前定义,避免遗漏调用。
2. 利用libc提供的内存大小查询函数
部分libc实现提供了直接查询内存块大小的函数,比如glibc的malloc_usable_size,可以直接传入free的指针获取该内存块的可用大小:
#include <malloc.h> #include <stdlib.h> void my_free(void* ptr) { if (!ptr) return; size_t freed_size = malloc_usable_size(ptr); // 用该大小更新统计数据 free(ptr); }
缺点:这种方法依赖具体的libc实现,不具备跨平台/跨版本兼容性,且返回的大小可能包含内存对齐或块管理的额外空间,和用户实际申请的大小有细微差异。
3. 维护指针-大小映射哈希表
在分配内存时,把返回的指针、对应的大小以及调用方PC地址存入全局哈希表,释放时通过指针查找对应的大小:
- 分配阶段:调用
__builtin_return_address(0)获取调用方PC,将指针、大小、PC一起存入哈希表,同时更新该PC的总分配统计; - 释放阶段:通过指针在哈希表中查找对应的大小和PC,更新该PC的总占用统计,然后删除哈希表条目并释放内存。
示例思路(结合uthash哈希库):
#include <stdlib.h> #include <stddef.h> #include <pthread.h> #include "uthash.h" // 哈希表条目结构 typedef struct { void* ptr; // 分配的内存指针 size_t size; // 申请的内存大小 void* caller_pc; // 调用malloc的代码地址 UT_hash_handle hh; // uthash的内部处理结构 } MemTrackEntry; static MemTrackEntry* mem_track_map = NULL; static pthread_mutex_t track_mutex = PTHREAD_MUTEX_INITIALIZER; void* my_malloc(size_t size) { void* ptr = malloc(size); if (!ptr) return NULL; void* pc = __builtin_return_address(0); pthread_mutex_lock(&track_mutex); // 创建并插入哈希表条目 MemTrackEntry* entry = malloc(sizeof(MemTrackEntry)); entry->ptr = ptr; entry->size = size; entry->caller_pc = pc; HASH_ADD_PTR(mem_track_map, ptr, entry); // 更新该PC的内存分配统计(比如你的全局Top统计哈希表) pthread_mutex_unlock(&track_mutex); return ptr; } void my_free(void* ptr) { if (!ptr) return; pthread_mutex_lock(&track_mutex); MemTrackEntry* entry; // 通过指针查找哈希表条目 HASH_FIND_PTR(mem_track_map, &ptr, entry); if (entry) { size_t freed_size = entry->size; void* pc = entry->caller_pc; // 更新该PC的内存释放统计 // 删除条目并释放内存 HASH_DEL(mem_track_map, entry); free(entry); } pthread_mutex_unlock(&track_mutex); free(ptr); }
缺点:哈希表本身会占用额外内存,多线程场景下的锁操作会带来一定性能开销,更适合调试诊断场景使用。
内容的提问来源于stack exchange,提问作者some user
相关产品推荐
相关产品推荐

