【问题标题】:Freeing memory of structure linked list using expiration of function scope使用函数范围到期释放结构链表的内存
【发布时间】:2011-05-19 02:54:43
【问题描述】:

我的目标是重复运行 API 调用并检查内存泄漏。
API 接受整数输入并返回指向结构链表中第一个结构的指针作为输出。每个结构可能有其他类型的结构变量。
在下面的代码中,我试图代表我的问题。

问题出在 callApi() 函数中。我需要处理 API() 返回的结构“输出”占用的内存。即使我在这里使用 free(output),它也会导致内存泄漏,因为它指向嵌套结构的链表。 (信息来源:http://en.wikibooks.org/wiki/C_Programming/Memory_management

问题: 离开退出 callApi() 调用时,当控制从函数返回到 main() 时,“输出”嵌套结构是否会过期?它会释放占用的整个内存吗?
请提出解决此内存泄漏问题的方法。

Can this problem be overcome with C++?

typedef struct{
  int dev_size;
  char *dev_name;
  dev_stat *next_dev;
  mem_stat *mem_info;
} dev_stat

typedef struct{
  int mem_capacity;
  char *mem_name;
} mem_stat

int main()
{
  int input;
  int return_val;
  int callApi(int);
  while(1)
  {
     return_val=callApi(input);
     print return_val;
  }
}

int callApi(int ip)
{
  //Update: Memory allocation is unnecessary as it is done inside the API() call itself
  //dev_stat *output=(dev_stat *)calloc(2,sizeof(dev_stat));
  int ret_val;
  ret_val=API(ip,&output);
  free(output);
  output=NULL;
  return ret_val;
}

【问题讨论】:

  • 什么是'int callApi(int);'在你的主要做什么?
  • 该程序只是为了给出程序流程的一般概念。它不完全符合 C 语法。使用 callApi() 的原因:如果我在 main() 中调用 API(),则使用的变量将永远不会超出范围,直到程序结束。因此在 callApi() 中调用 API(),而后者又在 main() 中的无限循环中调用
  • 这个问题可以用 C++ 解决吗?
  • @kk:在 C++ 中,您可能有 dev_namestd::stringnext_devmem_info 智能指针,因此您的结构会在释放时正确释放所有内存。但只要你的 API 不提供 C++ 风格的结构作为其输出,你就会陷入 C 风格的手动释放。

标签: c memory-management memory-leaks scope


【解决方案1】:

简单的答案是,不,退出函数时内存不会“过期”。

API应该提供一种“释放”返回值的方法,如果它是一个复杂的结构。如果没有,那么自己遍历结构并释放它可能是唯一的出路。

【讨论】:

    【解决方案2】:

    第一个问题谁是您要释放的结构的所有者

    API 可能会返回一个指向其内部结构的指针,您不能解除分配(例如,它可能是共享的)。

    您的代码也可能负责释放结构本身,而不是结构指向的其他结构。这样,您只需释放返回的结构并忘记它。

    但是,您的职责可能是从返回的结构开始释放整个对象树。在这种情况下,可以预期 API 具有一些功能,可以为您正确地释放结构及其后代。如果不是(很可能不是这种情况),您必须递归地释放结构引用的所有资源。

    您应该查看 APi 文档,以了解您的情况是否属于这三种情况。


    更新:
    明确地针对您的情况(整个结构应该手动释放),我会使用类似的东西:

    void free_mem_stat(struct mem_stat* p)
    {
        if (!p) return;
        free(p->mem_name);
        free(p);
    }
    
    void free_dev_stat(struct dev_stat* p)
    {
        // first, clean up the leaves
        for(struct dev_stat* curr = p; curr; curr = curr->next_dev)
        {
            free(curr->dev_name);
            free_mem_stat(curr->mem_info);
        }
        // than, clean up the linked list
        for(struct dev_stat* curr = p; curr; /**/)
        {
            struct dev_stat* next = curr->next_dev;
            free(curr);
            curr = next;
        }
    }
    
    int callApi(int ip)
    {
        int ret_val;
        struct dev_stat* output;
        ret_val = API(ip, &output);
        free_dev_stat(output);
        return ret_val;
    }
    

    注意free_dev_stat这样的函数应该由API自己提供,如果API开发者真的打算让用户释放他们的结构。

    【讨论】:

    • 结构是 API 的输出。所以 API 不会释放它。我想唯一的选择是递归释放结构。
    • @kk:在你的情况下,谁在分配next_dev?奇怪的是你必须自己分配第一个结构,而不是下一个。
    • 对 next_dev 的分配是在第三方 API 调用 API() 中完成的。
    • 我认为没有必要为第一个结构分配内存。我更新代码以删除 calloc 分配。
    • @kk:添加了释放器的示例
    猜你喜欢
    • 2016-08-27
    • 2014-02-13
    • 2015-06-07
    • 2019-01-19
    • 2016-10-25
    • 2023-03-15
    • 2022-12-04
    • 1970-01-01
    • 2014-11-12
    相关资源
    最近更新 更多