You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 21:57:46