完全释放链表的麻烦
Troubles with completely freeing a linked list
我用 C 编写了一个简单的程序,试图更好地理解链表的工作原理,但我很难让我的程序释放链表使用的资源。
我实现了两个函数(push 和 apppend)在列表顶部添加一个元素,另一个在列表底部添加一个元素。我正在使用第三个函数来释放链表使用的 space。
我的程序只是用一些值填充链表,然后调用函数“destroy_list”来释放链表使用的内存。但是由于某种原因,当我用 append() 填充我的列表时,似乎并没有释放列表使用的所有内存。
这是代码+我在用 push() 和 append() 填充链表时记录的内存使用情况的一些截图:
#include <stdlib.h>
#include <stdio.h>
#include <Windows.h> // used for Sleep(), use <unistd.h> for linux(?)
typedef struct LinkedList
{
void* data;
struct LinkedList* next;
} LinkedList;
void push(LinkedList** head, void* data_ptr)
{
LinkedList* new = malloc(sizeof(LinkedList));
new->next = *head;
new->data = data_ptr;
*head = new;
}
void append(LinkedList* node, void* data_ptr)
{
while (node->next != NULL)
node = node->next;
LinkedList* new = malloc(sizeof(LinkedList));
new->data = data_ptr;
new->next = NULL;
node->next = new;
}
void destroy_list(LinkedList** head)
{
LinkedList* current_node = *head;
LinkedList* next_node;
while (current_node != NULL)
{
next_node = current_node->next;
free(current_node);
current_node = next_node;
}
*head = NULL;
}
int main(void)
{
// create initial head for the list
LinkedList* list = malloc(sizeof(LinkedList));
list->next = NULL;
list->data = NULL;
Sleep(1000); // added delay to better see the memory usage
// trying to fill the list with both methods and compare the result of memory usage
for (int i = 0; i < 20000; i++)
{
//append(list, NULL);
push(&list, NULL);
}
Sleep(1000);
// trying to free all struct LinkedList
destroy_list(&list);
system("Pause");
return EXIT_SUCCESS;
}
(我没有把 malloc 指针检查放在代码中,让它更清楚一点。)
所以当我尝试用函数 push() 填充链表时,我得到了一种正常的行为,因为几乎所有在 filling/freeing 之前和之后的内存列表几乎是相同的(即使这不是完全相同的数量)。这是我截取的屏幕截图:
我在为每个测试向列表添加元素之前和之后添加了延迟,以便我们可以更好地看到差异。
因此,通过使用 push() 填充链表,我们在程序结束时获得了大约 900kb 的内存使用量。
现在这是完全相同程序的结果,但我们使用 append() 来填充列表:
正如我们所见,填充链表需要更多时间,因为 append() 方法必须遍历整个列表才能添加 push() 方法不需要的元素。最后,该程序释放的内存几乎没有以前的方法那么多。
所以我认为我的 append() 函数应该有问题,可能是某种内存泄漏导致链表中的节点脱离链。
然后我用 append() 函数做了更多测试,我注意到一个更奇怪的行为。当我尝试在 destroy_list() 函数中循环时增加一个变量,然后打印结果以查看程序调用 free() 的次数,突然释放了更多内存!
这里是修改后的 destroy_list() 函数:
void destroy_list(LinkedList** head)
{
LinkedList* current_node = *head;
LinkedList* next_node;
int i = 0; // Added
while (current_node != NULL)
{
next_node = current_node->next;
free(current_node);
current_node = next_node;
i++; // Added
}
printf("%d\n", i); // Added
*head = NULL;
}
使用这个函数并使用 append() 函数填充列表,我们得到:
我尝试了很多次,我提供的每个屏幕截图仍然得到相同的结果。
我真的不明白这怎么可能,但我花了很多时间在这上面,我真的很想知道我错过了什么???
检查进程使用的内存并不能很好地指示您是否正确释放了所有内存。当进程将内存返回给 OS 时,不必与对 free
.
的调用同时进行
Linux 上有诸如 Valgrind 之类的工具,专门用于检查 运行 代码中的内存错误。当我通过 Valgrind 运行 这段代码时,它回来了。没有无效的内存访问,所有分配的指针都被释放。
我用 C 编写了一个简单的程序,试图更好地理解链表的工作原理,但我很难让我的程序释放链表使用的资源。
我实现了两个函数(push 和 apppend)在列表顶部添加一个元素,另一个在列表底部添加一个元素。我正在使用第三个函数来释放链表使用的 space。
我的程序只是用一些值填充链表,然后调用函数“destroy_list”来释放链表使用的内存。但是由于某种原因,当我用 append() 填充我的列表时,似乎并没有释放列表使用的所有内存。
这是代码+我在用 push() 和 append() 填充链表时记录的内存使用情况的一些截图:
#include <stdlib.h>
#include <stdio.h>
#include <Windows.h> // used for Sleep(), use <unistd.h> for linux(?)
typedef struct LinkedList
{
void* data;
struct LinkedList* next;
} LinkedList;
void push(LinkedList** head, void* data_ptr)
{
LinkedList* new = malloc(sizeof(LinkedList));
new->next = *head;
new->data = data_ptr;
*head = new;
}
void append(LinkedList* node, void* data_ptr)
{
while (node->next != NULL)
node = node->next;
LinkedList* new = malloc(sizeof(LinkedList));
new->data = data_ptr;
new->next = NULL;
node->next = new;
}
void destroy_list(LinkedList** head)
{
LinkedList* current_node = *head;
LinkedList* next_node;
while (current_node != NULL)
{
next_node = current_node->next;
free(current_node);
current_node = next_node;
}
*head = NULL;
}
int main(void)
{
// create initial head for the list
LinkedList* list = malloc(sizeof(LinkedList));
list->next = NULL;
list->data = NULL;
Sleep(1000); // added delay to better see the memory usage
// trying to fill the list with both methods and compare the result of memory usage
for (int i = 0; i < 20000; i++)
{
//append(list, NULL);
push(&list, NULL);
}
Sleep(1000);
// trying to free all struct LinkedList
destroy_list(&list);
system("Pause");
return EXIT_SUCCESS;
}
(我没有把 malloc 指针检查放在代码中,让它更清楚一点。)
所以当我尝试用函数 push() 填充链表时,我得到了一种正常的行为,因为几乎所有在 filling/freeing 之前和之后的内存列表几乎是相同的(即使这不是完全相同的数量)。这是我截取的屏幕截图:
我在为每个测试向列表添加元素之前和之后添加了延迟,以便我们可以更好地看到差异。
因此,通过使用 push() 填充链表,我们在程序结束时获得了大约 900kb 的内存使用量。
现在这是完全相同程序的结果,但我们使用 append() 来填充列表:
正如我们所见,填充链表需要更多时间,因为 append() 方法必须遍历整个列表才能添加 push() 方法不需要的元素。最后,该程序释放的内存几乎没有以前的方法那么多。
所以我认为我的 append() 函数应该有问题,可能是某种内存泄漏导致链表中的节点脱离链。
然后我用 append() 函数做了更多测试,我注意到一个更奇怪的行为。当我尝试在 destroy_list() 函数中循环时增加一个变量,然后打印结果以查看程序调用 free() 的次数,突然释放了更多内存!
这里是修改后的 destroy_list() 函数:
void destroy_list(LinkedList** head)
{
LinkedList* current_node = *head;
LinkedList* next_node;
int i = 0; // Added
while (current_node != NULL)
{
next_node = current_node->next;
free(current_node);
current_node = next_node;
i++; // Added
}
printf("%d\n", i); // Added
*head = NULL;
}
使用这个函数并使用 append() 函数填充列表,我们得到:
我尝试了很多次,我提供的每个屏幕截图仍然得到相同的结果。
我真的不明白这怎么可能,但我花了很多时间在这上面,我真的很想知道我错过了什么???
检查进程使用的内存并不能很好地指示您是否正确释放了所有内存。当进程将内存返回给 OS 时,不必与对 free
.
Linux 上有诸如 Valgrind 之类的工具,专门用于检查 运行 代码中的内存错误。当我通过 Valgrind 运行 这段代码时,它回来了。没有无效的内存访问,所有分配的指针都被释放。