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

删除包含相同对象的多个独立链表时如何避免double free()错误

解决方案

方案1:为动态对象引入引用计数(最通用)

这是C/C++场景下处理共享堆内存的常规方案,核心逻辑是给每个动态对象增加引用计数标记,只有计数归0时才真正释放对象。

改造步骤:

  1. 在Object结构体中新增ref_count字段,对象创建时初始化为1
  2. 新增引用操作、释放引用操作两个辅助函数
typedef struct Object {
  // 原有对象字段保留
  int ref_count; // 新增引用计数字段
} Object;

// 原有对象创建函数修改
Object* create_object() {
  Object* obj = malloc(sizeof(Object));
  // 原有初始化逻辑保留
  obj->ref_count = 1;
  return obj;
}

// 新增:增加引用
void obj_ref(Object* obj) {
  if (obj != NULL) obj->ref_count++;
}

// 新增:释放引用,计数归0时真正释放对象
void obj_unref(Object* obj) {
  if (obj == NULL) return;
  obj->ref_count--;
  if (obj->ref_count == 0) {
    // 调用你原有对象释放逻辑
    delete_object_function(obj);
  }
}
  1. 链表操作适配规则:
  • 往链表插入对象时,调用obj_ref(待插入对象),标记链表持有该对象的一份引用
  • 删除链表时,给delete_list传入的释放函数替换为obj_unref,不要直接调用对象释放函数

改造后你原来的报错场景就可以正常运行:对象创建后计数为1,插入两个链表时各加1次计数变为3,删除第一个链表计数减为2,删除第二个链表计数减为1,你自己持有对象指针的逻辑如果不再需要该对象,再调用一次obj_unref计数就会归0自动释放,不会出现double free,也不会内存泄漏。

方案2:外置引用计数哈希表(无需修改原有对象结构)

如果你不能修改Object的结构体定义,可以用全局哈希表存储所有动态对象的地址和对应的引用计数,逻辑和方案1完全一致,只是把计数存在哈希表而非对象内部。
该方案的缺点是多线程场景下需要对哈希表加锁,性能略低于内置引用计数。

方案3:全局对象池统一回收(适合短生命周期程序)

如果你的程序运行周期短、对象总占用内存可控,可以引入全局对象池:所有create_object生成的对象都先注册到对象池中,所有链表删除时都不释放持有的对象,等程序即将退出前,统一遍历对象池释放所有对象。
该方案实现最简单,完全规避double free问题,适合小型工具类项目使用。

注意事项

  • 引用计数方案需要*严格遵守「获取指针时加引用、放弃指针时减引用」*的约定,避免出现逻辑漏洞
  • 如果存在对象间循环引用的场景,引用计数无法自动回收,需要手动打断循环引用关系,或改用标记清除式的内存回收逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 23:12:04