free() 函数只释放结构的第一个元素?
free() function only frees the first element of a struct?
我正在使用两个结构:
typedef struct ListNode{
void* value;
struct ListNode *next;
struct ListNode *prev;
} Node;
typedef struct List{
Node *first;
Node *last;
int count;
} List;
然后我声明这些变量并分配内存
List *x = calloc(1,sizeof(List));
Node *x1 = malloc(sizeof(Node));
Node *x2 = malloc(sizeof(Node));
x->first = x1;
x->last =x2;
x->count = 2;
free(x);
所以我很确定如果我释放 x
,x->count
、x->first
、x->last
也会消失。然而,在这种情况下,我使用 gdb 进行检查,令人惊讶的是只有 x 的第一个元素被删除(例如:如果在结构 List
中我将计数放在顶部,那么它只会删除计数并留下完好无损)。为什么会这样,我如何 free()
整个结构?
你的假设是错误的。如果你这样做 free(x)
你只是释放了保存 x
内容的内存块,但是由于 这个块包含一些指向其他块的指针 ,你将首先需要 free()
那些。这是因为 free()
不关心你正在释放的内存的内容,它不会做任何花哨的事情。如果在使用 free()
后看到某些值被修改,那只是因为 free()
使用该内存存储一些有用的内部值以跟踪内存使用情况,如果 [=30] 发生这种情况只是巧合=] 结构中的指针。
free()
结构的正确方法如下:
free(x->first);
free(x->last);
// DO NOT free(x->count), it's an integer, not a previously allocated pointer!
free(x);
这是一个可视化表示(请原谅我糟糕的笔迹):
了解结构的内存布局很重要...我不是专家所以这将非常简化:
列表 x = [pointer-to-x1][pointer-to-x2][int](加上填充)
因此,当您 运行 calloc(1, sizeof(List)) 时,您并不是在与 List 相同的内存区域中创建 x1 和 x2 结构,因为它们只是指向某些记忆中的其他地方。您只是在创建对它们的小参考,甚至还没有设置。这就是为什么你必须分别 malloc x1 和 x2。
因此,当您释放 (x) 时,您也不会释放 x1 或 x2。 free 不知道如何,也不知道您 运行 x1 和 x2 的 malloc。如果它试图释放它,它可能会过早释放内存或释放堆栈上的内存。它只会查看我上面映射的内存区域。
正在写这篇文章,看到另一个答案刚刚进来。Marco 的答案很好!
您似乎对调用 free
时会发生什么抱有无效的期望。
您无法在 GDB 中验证 free
的结果。
释放内存位置并不意味着该位置的内存以任何方式被修改。它可能看起来仍然和以前一样。 OS 或 C 运行时库可能会将其设置为全零,但这不是强制性的。指针x
也不会改变。
释放一个地址只意味着你告诉 OS 它可以收回它并给别人。
调用 free
后,您将不再被允许访问内存。
这就是 free
之后发生的所有事情。
因此last
和count
不会"disappear"。
就是说,正如其他人已经指出的那样,您也存在内存泄漏。释放 x
不会释放任何其他可通过 x->first
或 x->last
.
访问的内存
我正在使用两个结构:
typedef struct ListNode{
void* value;
struct ListNode *next;
struct ListNode *prev;
} Node;
typedef struct List{
Node *first;
Node *last;
int count;
} List;
然后我声明这些变量并分配内存
List *x = calloc(1,sizeof(List));
Node *x1 = malloc(sizeof(Node));
Node *x2 = malloc(sizeof(Node));
x->first = x1;
x->last =x2;
x->count = 2;
free(x);
所以我很确定如果我释放 x
,x->count
、x->first
、x->last
也会消失。然而,在这种情况下,我使用 gdb 进行检查,令人惊讶的是只有 x 的第一个元素被删除(例如:如果在结构 List
中我将计数放在顶部,那么它只会删除计数并留下完好无损)。为什么会这样,我如何 free()
整个结构?
你的假设是错误的。如果你这样做 free(x)
你只是释放了保存 x
内容的内存块,但是由于 这个块包含一些指向其他块的指针 ,你将首先需要 free()
那些。这是因为 free()
不关心你正在释放的内存的内容,它不会做任何花哨的事情。如果在使用 free()
后看到某些值被修改,那只是因为 free()
使用该内存存储一些有用的内部值以跟踪内存使用情况,如果 [=30] 发生这种情况只是巧合=] 结构中的指针。
free()
结构的正确方法如下:
free(x->first);
free(x->last);
// DO NOT free(x->count), it's an integer, not a previously allocated pointer!
free(x);
这是一个可视化表示(请原谅我糟糕的笔迹):
了解结构的内存布局很重要...我不是专家所以这将非常简化:
列表 x = [pointer-to-x1][pointer-to-x2][int](加上填充)
因此,当您 运行 calloc(1, sizeof(List)) 时,您并不是在与 List 相同的内存区域中创建 x1 和 x2 结构,因为它们只是指向某些记忆中的其他地方。您只是在创建对它们的小参考,甚至还没有设置。这就是为什么你必须分别 malloc x1 和 x2。
因此,当您释放 (x) 时,您也不会释放 x1 或 x2。 free 不知道如何,也不知道您 运行 x1 和 x2 的 malloc。如果它试图释放它,它可能会过早释放内存或释放堆栈上的内存。它只会查看我上面映射的内存区域。
正在写这篇文章,看到另一个答案刚刚进来。Marco 的答案很好!
您似乎对调用 free
时会发生什么抱有无效的期望。
您无法在 GDB 中验证 free
的结果。
释放内存位置并不意味着该位置的内存以任何方式被修改。它可能看起来仍然和以前一样。 OS 或 C 运行时库可能会将其设置为全零,但这不是强制性的。指针x
也不会改变。
释放一个地址只意味着你告诉 OS 它可以收回它并给别人。
调用 free
后,您将不再被允许访问内存。
这就是 free
之后发生的所有事情。
因此last
和count
不会"disappear"。
就是说,正如其他人已经指出的那样,您也存在内存泄漏。释放 x
不会释放任何其他可通过 x->first
或 x->last
.