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

使用malloc_hook追踪内存时memory_bytes_hook出现负值的原因排查

malloc_hook追踪内存出现负值的原因及解决思路

你遇到的memory_bytes_hook变为负值的情况,核心是内存统计的收支不平衡——要么部分内存分配没被统计,要么释放操作被重复/错误统计,结合你的代码和malloc_hook特性,具体原因如下:

1. 未覆盖所有内存操作入口

你的代码只hook了malloc、free、realloc,但标准库还有其他内存操作函数没处理:

  • calloc:该函数分配内存并初始化,对应钩子是__calloc_hook,若程序调用calloc,你的代码不会统计这部分分配,但后续free时会减去对应大小,直接导致统计值减少。
  • memalign/posix_memalign:这类对齐分配的函数也有专属钩子,被调用后会漏统计。
  • 部分第三方库自带内存管理(比如直接用mmap申请内存),这类操作不会被malloc_hook捕获,若后续用free释放(不符合规范但可能发生),会错误减去不存在的分配量。

2. realloc特殊场景处理错误

当调用realloc(ptr, 0)时,标准库行为等价于free(ptr)并返回NULL。你的代码会先执行:

memory_bytes_hook += (0 - oldSize); // 这里已经减去了内存块大小

但realloc内部调用的free会触发你的my_free_hook,再次执行memory_bytes_hook -= oldSize,相当于同一个内存块被重复减两次,直接导致统计值过度减少。

3. 非法free操作导致错误统计

如果程序出现以下情况,统计逻辑会出错:

  • 重复free同一个指针:每次free都会触发钩子,重复减去该内存块大小,多次操作后必然出现负值。
  • free非malloc分配的内存:比如free栈上指针、mmap申请的内存,此时malloc_usable_size(ptr)会返回随机值(甚至很大的数),减去后直接让统计值暴跌至负数。

4. malloc_hook被覆盖

malloc_hook是全局变量,若程序中其他模块(比如第三方库)也设置了自己的malloc_hook,会覆盖你的钩子:

  • 如果分配操作被其他钩子处理而没被你的代码统计,但释放操作仍由你的钩子处理,就会出现“只减不增”的情况,最终导致负值。

对应的修复思路

  1. 补全所有内存操作钩子:添加__calloc_hook、__memalign_hook等的处理函数,确保所有标准库内存分配都被统计。
  2. 修复realloc特殊场景:在my_realloc_hook中判断size == 0的情况,直接调用free并更新统计,避免重复触发free_hook:
    static void* my_realloc_hook (void *ptr, size_t size, const void *caller)
    {
       const std::lock_guard<std::mutex> lock(memory_mutex_hook);
       __malloc_hook = nullptr;
       __free_hook = nullptr;
       __realloc_hook = nullptr;
       
       if (size == 0 && ptr != nullptr) {
           long int oldSize = malloc_usable_size(ptr);
           free(ptr);
           memory_bytes_hook -= oldSize;
           my_init_hook();
           return nullptr;
       }
       
       long int oldSize = malloc_usable_size(ptr);
       void *result = realloc(ptr, size);
       long int updated_size = malloc_usable_size(result);
       memory_bytes_hook += (updated_size - oldSize);
       if(peak_memory_hook < memory_bytes_hook )
            peak_memory_hook = memory_bytes_hook ;
       my_init_hook();
       return result;
    }
    
  3. 跟踪已分配指针:维护一个哈希表(比如std::unordered_map),在分配钩子中记录指针和对应大小,在free钩子中先检查指针是否存在:
    • 存在则减去对应大小并移除记录
    • 不存在则跳过统计(或打印日志排查非法free)
  4. 避免钩子被覆盖:改用LD_PRELOAD机制加载自定义malloc库,这种方式优先级更高,能避免被其他模块覆盖钩子。

附原问题代码

long int memory_bytes_hook = 0;
long int peak_memory_hook = 0;
std::mutex memory_mutex_hook;
static void my_init_hook (void);
static void *my_malloc_hook (size_t, const void *);
static void my_free_hook (void*, const void *);
static void* my_realloc_hook (void *ptr, size_t size, const void *caller);
static void *(*old_malloc_hook)(size_t, const void *);
static void (*old_free_hook)(void*, const void *);
static void *(*old_realloc_hook)(void *ptr, size_t size, const void *caller);


static void
my_init_hook (void)
{
  __malloc_hook = my_malloc_hook;
  __free_hook = my_free_hook;
  __realloc_hook = my_realloc_hook ;
}

static  void *
my_malloc_hook (size_t size, const void *caller)
{
  const std::lock_guard<std::mutex> lock(memory_mutex_hook);
  void *result;

  __malloc_hook = nullptr;
  __free_hook = nullptr ;
  __realloc_hook = nullptr ;
  result = malloc (size);
  memory_bytes_hook += malloc_usable_size(result);
  if(peak_memory_hook  < memory_bytes_hook )
    peak_memory_hook = memory_bytes_hook ;
  my_init_hook();
  return result;
}

static void* my_realloc_hook (void *ptr, size_t size, const void *caller)
{
   const std::lock_guard<std::mutex> lock(memory_mutex_hook);
   __malloc_hook = nullptr;
   __free_hook = nullptr;//old_free_hook ;
   __realloc_hook = nullptr;//old_realloc_hook ;
   long int oldSize = malloc_usable_size(ptr);
   void *result = realloc(ptr, size);
   long int updated_size = malloc_usable_size(result);
   memory_bytes_hook += (updated_size - oldSize);
   if(peak_memory_hook  < memory_bytes_hook )
        peak_memory_hook = memory_bytes_hook ;
   my_init_hook();
   return result;

}

static void
my_free_hook (void *ptr, const void *caller)
{
   const std::lock_guard<std::mutex> lock(memory_mutex_hook);
   __malloc_hook = nullptr;// old_malloc_hook;
   __free_hook = nullptr;// old_free_hook ;
   __realloc_hook = nullptr;//old_realloc_hook ;
  /* Call recursively */
  long int oldSize = malloc_usable_size(ptr);
  free (ptr);
  memory_bytes_hook -= oldSize;
  if(peak_memory_hook  < memory_bytes_hook )
        peak_memory_hook = memory_bytes_hook ;
  my_init_hook();
}



int main(int argc, char** argv)
{
    my_init_hook();

    ... calling other libraries and do lot of operation for couple of hours...

     std::cout <<"At last: peak_memory hook: "<< peak_memory_hook << "	" << " Bytes 
     allocated: " << memory_bytes_hook << "
";
    return 0;
}

内容的提问来源于stack exchange,提问作者Raj Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 03:15:48