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 中。 (除了malloc
、calloc
、realloc
之外,没有标准 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
的调用中可以重用该块。因此,执行malloc
和free
的程序可能不会将之前使用的所有内存释放给内核。另见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() 后释放内存的主要内容,如果未能解决你的问题,请参考以下文章