【问题标题】:Memory leak in the following C code以下 C 代码中的内存泄漏
【发布时间】:2011-09-13 10:21:53
【问题描述】:

对于以下代码示例,存在内存泄漏。在以下情况下如何防止内存泄漏:

            1 #include <stdio.h>
            2 #include <stdlib.h>
            3 
            4 typedef struct sample_help {
            5 int *value;
            6 void **pointers;
            7 }*sample,sample_node;
            8 
            9 
            10 sample main(){
            11 sample  ABC=NULL; 
            12 sample  XYZ=NULL;
            13 sample  kanchi = NULL;
            14 
            15 ABC = malloc(sizeof(sample_node));
            16 XYZ = malloc(sizeof(sample_node));
            17 ABC->pointers = malloc(5*sizeof(void *));
            18 XYZ->pointers = malloc(5*sizeof(void *));
            19 ABC->value = malloc(5*sizeof(int));
            20 XYZ->value = malloc(5*sizeof(int));
            21 
            22 ABC->value[0] = 10;
            23 ABC->value[1] = 20;
            24 
            25 XYZ->pointers[0] = ABC;
            26 kanchi = XYZ->pointers[0];
            27 
            28 printf("::::%d\n",XYZ->pointers[0]);
            29 printf("kanchi1:::::%d\n",kanchi->value[0]);
            30 
            31 
            32 return XYZ;
            33 }
            34 

以下是 valgrind 的输出。

==27448== 
==27448== HEAP SUMMARY:
==27448==     in use at exit: 152 bytes in 6 blocks 
==27448==   total heap usage: 6 allocs, 0 frees, 152 bytes allocated
==27448== 
==27448== 152 (16 direct, 136 indirect) bytes in 1 blocks are definitely lost in loss  record 6 of 6
==27448==    at 0x4C244E8: malloc (vg_replace_malloc.c:236)
==27448==    by 0x40056B: main (test2.c:16)
==27448== 
==27448== LEAK SUMMARY:
==27448==    definitely lost: 16 bytes in 1 blocks
==27448==    indirectly lost: 136 bytes in 5 blocks
==27448==      possibly lost: 0 bytes in 0 blocks
==27448==    still reachable: 0 bytes in 0 blocks
==27448==         suppressed: 0 bytes in 0 blocks  
==27448== 

【问题讨论】:

  • @thetna 你确定这合法吗?
  • @thetna ...您的逻辑真的严重损坏。
  • @thetna 为了澄清错误的逻辑,这就像说 0 的平方是 0 而 1 的平方是 1 因此,任何数字的平方都是它自己。
  • @thetna: 好的 - 在这种情况下,你应该实现这是一个正确的函数,然后如果你想测试它,可以从 main 调用它。
  • @thetna:请参阅下面的答案,了解如何 (a) 正确实现此功能(不滥用 main())以及 (b) 完成后如何释放调用方的内存。

标签: c memory-management memory-leaks valgrind


【解决方案1】:

你的代码应该更像这样:

#include <stdio.h>
#include <stdlib.h>

typedef struct sample_help {
    int *value;
    void **pointers;
} *sample, sample_node;

sample foo(void)
{
    sample  ABC=NULL;
    sample  XYZ=NULL;
    sample  kanchi = NULL;

    ABC = malloc(sizeof(sample_node));
    XYZ = malloc(sizeof(sample_node));
    ABC->pointers = malloc(5*sizeof(void *));
    XYZ->pointers = malloc(5*sizeof(void *));
    ABC->value = malloc(5*sizeof(int));
    XYZ->value = malloc(5*sizeof(int));

    ABC->value[0] = 10;
    ABC->value[1] = 20;

    XYZ->pointers[0] = ABC;
    kanchi = XYZ->pointers[0];

    printf("::::%d\n",XYZ->pointers[0]);
    printf("kanchi1:::::%d\n",kanchi->value[0]);

    return XYZ;
}

int main(void)
{
    // call your function
    sample xyz = foo();

    // ... do something with the data structure xyz ...

    // free memory allocated by your function
    free(xyz->pointers[0]->value);    // free ABC->value
    free(xyz->pointers[0]->pointers); // free ABC->pointers
    free(xyz->pointers[0]);           // free ABC
    free(xyz->value);                 // free XYZ->value
    free(xyz->pointers);              // free XYZ->pointers
    free(xyz);                        // free XYZ

    return 0;
}

请注意,我们在完成后将数据结构从 main() 中释放出来。

【讨论】:

    【解决方案2】:

    在不再需要时释放已使用的内存:

    free(ABC->value);
    free(XYZ->value);
    free(ABC->pointers);
    free(XYZ->pointers);
    free(ABC);
    free(XYZ);
    

    顺便说一句:当这是整个程序时,它实际上并不重要。由于操作系统会在进程结束时回收所有未释放的内存,因此不需要释放直到程序终止之前一直在使用的内存。不过,这是一种很好的做法。

    【讨论】:

    • 有了sample main(),我们知道没有操作系统:P
    • 如果我释放 XYZ 那么我如何返回结构?我想返回 XYZABCXYZpointers 中赋值。我们打个比方,在根节点中添加了一个节点。
    • 这种情况下 main() 的调用者需要在使用这些值后释放内存。以这种方式使用 main() 很奇怪,你能描述更多关于你正在做的更广泛的背景吗?
    • 你永远不知道其他人何时会拿走你的代码(甚至是你,6 个月后)并在不审查的情况下移动它。例如,考虑重命名这个 main() 函数,以便它可以在更深层次的程序中使用。由于这种潜力(即使很小),我不认为适当的内存管理仅仅是“好的做法”,我认为它是一个可靠的要求。
    • 不要释放 XYZ,返回一个指向它的指针,然后接收它的函数负责稍后释放它。
    【解决方案3】:

    现在已经在 cmets 中读取了您的更新,您的分配和返回内存的模块(称为 main())很好。

    无论哪个模块使用从您的模块返回的值,都需要在使用后释放数据。因此,如果您将模块实现为

    sample mymodule(void)
    {
        sample foo = malloc(10);
        /* set up contents of foo as required */
        return foo;
    }
    

    那么 mymodule 的调用者会这样:

    int main (int argc, char *argv[])
    {
        sample bar = mymodule();
        /* use contents of bar as required */
        free(bar);
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      相关资源
      最近更新 更多