C - strdup() 后释放内存

Posted

技术标签:

【中文标题】C - strdup() 后释放内存【英文标题】:C - Freeing memory after strdup() 【发布时间】:2014-09-20 13:29:18 【问题描述】:

我正在学习 Learn C the Hard way 在线课程。在下面的代码示例中,我不明白为什么需要两个 free() 调用。我以为只需要调用一次free(),因为只有一个malloc() 出现。有人能解释一下为什么我们需要两个吗?

如果我将 free(who->name); 注释掉,那么 valgrind 会告诉我我丢失了一大块记忆,就像这样;

LEAK SUMMARY:
definitely lost: 21 bytes in 2 blocks

代码如下:

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

struct Person 
    char *name;
    int age;
    int height;
    int weight;
;

struct Person *Person_create(char *name, int age, int height, int weight)

    struct Person *who = malloc(sizeof(struct Person));
    assert(who != NULL);

    who->name = strdup(name);
    who->age = age;
    who->height = height;
    who->weight = weight;

    return who;


void Person_destroy(struct Person *who)

    assert(who != NULL);

    free(who->name); /* Why this one??! */
    free(who);


int main(int argc, char *argv[])

    // make two people structures
    struct Person *joe = Person_create(
            "Joe Alex", 32, 64, 140);

    struct Person *frank = Person_create(
            "Frank Blank", 20, 72, 180);

    // destroy them both so we clean up
    Person_destroy(joe);
    Person_destroy(frank);

    return 0;

【问题讨论】:

因为 strdup() 也分配了内存,所以它必须被释放(参见doc)。 strdup 是伪装的malloc 阅读标准函数的文档比在 SO 上提问要更快 strdup 不是标准 C 函数,但它在 POSIX 中。 (除了malloccallocrealloc 之外,没有标准 C 函数返回需要释放的指针。 在 C99 以外的其他标准中可以提及标准函数。 Posix 就是这样一个标准。 【参考方案1】:

strdup(3) 被记录为

  The strdup() function returns a pointer to a new string which is a
  duplicate of the string s.  Memory for the new string is obtained
  with malloc(3), and can be freed with free(3).

顺便说一句,正如Matt McNabb 评论的那样,strdup 在 Posix 中是标准的,而不是在 C99 语言规范中。

当然free 只会释放你传递给它的内存区域(它不会神奇地间接释放你传递给它的内存区域内的任何区域)。同样,free(3) 说:

  The free() function frees the memory space pointed to by ptr, which
  must have been returned by a previous call to malloc(), calloc() or
  realloc().  Otherwise, or if free(ptr) has already been called
  before, undefined behavior occurs.  If ptr is NULL, no operation is
  performed.

阅读更多关于C dynamic memory allocation 的信息。如果您不喜欢这样,请了解garbage collection。在 Linux 和其他一些系统上使用 C,您可以考虑使用 Boehm's conservative garbage collector。然后,您将使用GC_MALLOC 和/或GC_MALLOC_ATOMIC 代替malloc,并使用GC_STRDUP 代替strdup,并且您不会为free 而烦恼(如果需要,您有时可以使用GC_FREE) .我觉得它非常有用,但它确实有一些缺点(比malloc 慢一点,并且没有明确保证释放内存......)。

了解memory corruption 和memory leaks

顺便说一句,您应该首先使用所有警告和调试信息编译您的程序(例如gcc -Wall -g)。然后你可以使用你的调试器(gdb),在到达main 之后在malloc 中设置一个断点,然后查看何时调用malloc。您会看到 strdup 正在调用 malloc ....


仅供参考,在 Linux 上,malloc 是使用 mmap(2) 实现的 - 有时是旧的 sbrk(2)- 系统调用 - 以获得“大”内存区域(几千字节甚至几兆字节),而 free 有时可能调用 munmap(2) - 对于这些大区域 - 但大多数情况下,它只是将已释放的块标记为可重用,以便在某些 未来malloc 的调用中可以重用该块。因此,执行mallocfree 的程序可能不会将之前使用的所有内存释放给内核。另见this question about memory fragmentation

也可以使用 Valgrind 和 address sanitizer

一些操作系统(例如 Linux)上,您可以使用 gcc -Wall -Wextra -g 编译您的 C 代码(使用 GCC),然后在运行时使用 valgrind 工具。它会减慢执行速度,但有助于发现 some 内存泄漏和 some buffer overflow 等错误。使用最近的 GCC 或 Clang 编译器,您还可以使用 -at compile time- its address sanitizer(检测生成的代码)。

您还可以阅读GC handbook,与内存分配和垃圾收集算法有关。

【讨论】:

以上是关于C - strdup() 后释放内存的主要内容,如果未能解决你的问题,请参考以下文章

函数strdup()

C语言free释放内存后为啥指针里的值不变?竟然还可以输出

C 语言二级指针案例 ( 多级指针内存释放问题 | 多级指针避免野指针 )

C语言 调用函数完后释放内存吗?

目标c-关闭集合视图控制器后未释放常驻内存和脏内存

在 C 中释放内存需要啥?