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

C语言自定义链表库出现内存泄漏,求排查代码问题

内存泄漏排查与修复方案

泄漏原因分析

1. 链表释放循环的致命错误

owl_sll_free函数中,释放节点后直接访问其next指针属于未定义行为,会导致循环提前终止,大量内存未被正确释放:

while (cursor)
{
    if (list->elfree)
        list->elfree(cursor->data);
    else
        free(cursor->data);

    free(cursor);
    cursor = cursor->next; // 错误:cursor已被释放,访问cursor->next非法
}

free(cursor)执行后,cursor变为野指针,此时读取cursor->next的结果不可预测,大概率会得到NULL,导致循环直接终止。仅释放了第一个节点(甚至可能一个都没释放),剩余节点的结构体内存、节点内的data块,以及data中指向的a1/a2都无法被释放,最终产生4份内存泄漏。

2. 对应泄漏点的具体来源

  • main.c中a1/a2的malloc泄漏:循环终止导致未调用elfree函数,无法释放节点内data指向的a1/a2;
  • node_init中的malloc泄漏:未释放剩余节点的owl_sll_node_t结构体内存和节点内的data内存块。

修复方案

1. 修正链表释放循环逻辑

在释放节点前提前保存下一个节点的指针,避免访问已释放的内存:

void owl_sll_free(owl_sll_t *list)
{
    if (!list) return; // 增加空指针检查,防止崩溃

    owl_sll_node_t *cursor = list->head;
    while (cursor)
    {
        owl_sll_node_t *next_node = cursor->next; // 提前保存下一个节点

        // 释放节点数据
        if (list->elfree)
            list->elfree(cursor->data);
        else
            free(cursor->data);

        // 释放节点本身
        free(cursor);

        cursor = next_node; // 使用保存的有效指针
    }

    free(list);
}

2. 其他潜在问题优化(非当前泄漏原因,但需注意)

  • owl_sll_bremove和owl_sll_fremove返回的data指针,需由调用者负责释放,需在文档中明确说明;
  • 用memcpy替代node_init中的手动内存拷贝,更简洁可靠:
    static owl_sll_node_t *node_init(void *data, size_t size)
    {
        static unsigned int id = 0;
        owl_sll_node_t *node = malloc(sizeof(owl_sll_node_t));
        if (!node) return NULL;
        
        node->data = malloc(size);
        if (!node->data) { free(node); return NULL; } // 分配失败时回滚
        
        memcpy(node->data, data, size);
        
        node->next = NULL;
        node->id = id++;
        return node;
    }
    
  • 所有malloc调用增加失败检查,避免空指针访问。

验证修复效果

重新编译代码后,执行leaks --atExit --list -- ./main命令,应无内存泄漏报告。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 07:10:29