C内存泄漏与valgrind
C Memory leak with valgrind
我正在尝试在开源项目中使用 C 中的链表实现队列。我已经实现了队列,编写了单元测试,并使用 valgrind 解决了大部分内存泄漏问题。
现在的问题是,几个小时以来,我一直在尝试查找这最后 8 个字节的泄漏,但我似乎无法弄清楚。
这是 valgrind 的输出:
==25806== 8 bytes in 1 blocks are definitely lost in loss record 1 of 1
==25806== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==25806== by 0x80484E3: node_create (in /home/karysto/c-datastructures/queue/tests.out)
==25806== by 0x8048511: enqueue (in /home/karysto/c-datastructures/queue/tests.out)
==25806== by 0x8048851: test_dequeue_updates_size (in /home/karysto/c-datastructures/queue/tests.out)
==25806== by 0x8048978: test_suite (in /home/karysto/c-datastructures/queue/tests.out)
==25806== by 0x80489B0: main (in /home/karysto/c-datastructures/queue/tests.out)
==25806==
==25806== LEAK SUMMARY:
==25806== definitely lost: 8 bytes in 1 blocks
==25806== indirectly lost: 0 bytes in 0 blocks
==25806== possibly lost: 0 bytes in 0 blocks
==25806== still reachable: 0 bytes in 0 blocks
==25806== suppressed: 0 bytes in 0 blocks
==25806==
这是队列链表的结构:
struct Queue {
int size;
struct Node *front;
struct Node *back;
};
struct Node {
int data;
struct Node *next;
};
这里是 queue.c
,dequeue
的实现。
void
dequeue(struct Queue *q) {
/* Dequeue from an empty queue. */
if (q->size == 0) {
return;
}
/* Dequeue the only node. */
else if (q->size == 1) {
q->front = NULL;
q->back = NULL;
free(q->front);
free(q->back);
}
/* Regular case. */
else if (q->size > 1) {
struct Node *temp;
temp = q->front;
q->front = q->front->next;
free(temp);
}
--(q->size);
return;
}
这是同一文件中的 enqueue
。
void
enqueue(struct Queue *q, int data) {
struct Node *head = node_create(data);
/* First enqueue on empty. */
if (q->front == NULL && q->back == NULL) {
q->front = head;
q->back = head;
}
else {
q->back->next = head;
q->back = head;
}
++(q->size);
return;
}
为了完整起见,这里是从 enqueue
引用的 node_create
函数:
struct Node*
node_create(int d) {
struct Node *n = malloc(sizeof(struct Node));
n->data = d;
n->next = NULL;
return n;
}
怎么样:
/* Dequeue the only node. */
else if (q->size == 1) {
free(q->front);
q->front = NULL;
q->back = NULL;
}
说明:在您的原始解决方案中,您首先将 q->front
和 q->back
都指向 NULL
,然后再 free()
将它们指向 NULL
。 运行 free()
在 NULL
doesn't destroy the universe 上,但它做的并不多,即没有 free()
访问你的最后一个节点。
我认为你的问题在于最后一个节点的出队:
/* Dequeue the only node. */
else if (q->size == 1) {
q->front = NULL;
q->back = NULL;
free(q->front);
free(q->back);
}
您实际上调用了 free(NULL)
两次。 free(NULL)
是允许的,但它不做任何事情。所以你最终没有释放节点并丢失内存。你应该在释放后分配NULL
到前面和后面,你也应该free
最后一个节点只一次:
/* Dequeue the only node. */
else if (q->size == 1) {
free(q->front);
q->front = NULL;
q->back = NULL;
}
(这里前后端是一样的,你出队的时候也是remob at most one node,所以你最多只能free 1 node。)
我正在尝试在开源项目中使用 C 中的链表实现队列。我已经实现了队列,编写了单元测试,并使用 valgrind 解决了大部分内存泄漏问题。
现在的问题是,几个小时以来,我一直在尝试查找这最后 8 个字节的泄漏,但我似乎无法弄清楚。
这是 valgrind 的输出:
==25806== 8 bytes in 1 blocks are definitely lost in loss record 1 of 1
==25806== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==25806== by 0x80484E3: node_create (in /home/karysto/c-datastructures/queue/tests.out)
==25806== by 0x8048511: enqueue (in /home/karysto/c-datastructures/queue/tests.out)
==25806== by 0x8048851: test_dequeue_updates_size (in /home/karysto/c-datastructures/queue/tests.out)
==25806== by 0x8048978: test_suite (in /home/karysto/c-datastructures/queue/tests.out)
==25806== by 0x80489B0: main (in /home/karysto/c-datastructures/queue/tests.out)
==25806==
==25806== LEAK SUMMARY:
==25806== definitely lost: 8 bytes in 1 blocks
==25806== indirectly lost: 0 bytes in 0 blocks
==25806== possibly lost: 0 bytes in 0 blocks
==25806== still reachable: 0 bytes in 0 blocks
==25806== suppressed: 0 bytes in 0 blocks
==25806==
这是队列链表的结构:
struct Queue {
int size;
struct Node *front;
struct Node *back;
};
struct Node {
int data;
struct Node *next;
};
这里是 queue.c
,dequeue
的实现。
void
dequeue(struct Queue *q) {
/* Dequeue from an empty queue. */
if (q->size == 0) {
return;
}
/* Dequeue the only node. */
else if (q->size == 1) {
q->front = NULL;
q->back = NULL;
free(q->front);
free(q->back);
}
/* Regular case. */
else if (q->size > 1) {
struct Node *temp;
temp = q->front;
q->front = q->front->next;
free(temp);
}
--(q->size);
return;
}
这是同一文件中的 enqueue
。
void
enqueue(struct Queue *q, int data) {
struct Node *head = node_create(data);
/* First enqueue on empty. */
if (q->front == NULL && q->back == NULL) {
q->front = head;
q->back = head;
}
else {
q->back->next = head;
q->back = head;
}
++(q->size);
return;
}
为了完整起见,这里是从 enqueue
引用的 node_create
函数:
struct Node*
node_create(int d) {
struct Node *n = malloc(sizeof(struct Node));
n->data = d;
n->next = NULL;
return n;
}
怎么样:
/* Dequeue the only node. */
else if (q->size == 1) {
free(q->front);
q->front = NULL;
q->back = NULL;
}
说明:在您的原始解决方案中,您首先将 q->front
和 q->back
都指向 NULL
,然后再 free()
将它们指向 NULL
。 运行 free()
在 NULL
doesn't destroy the universe 上,但它做的并不多,即没有 free()
访问你的最后一个节点。
我认为你的问题在于最后一个节点的出队:
/* Dequeue the only node. */
else if (q->size == 1) {
q->front = NULL;
q->back = NULL;
free(q->front);
free(q->back);
}
您实际上调用了 free(NULL)
两次。 free(NULL)
是允许的,但它不做任何事情。所以你最终没有释放节点并丢失内存。你应该在释放后分配NULL
到前面和后面,你也应该free
最后一个节点只一次:
/* Dequeue the only node. */
else if (q->size == 1) {
free(q->front);
q->front = NULL;
q->back = NULL;
}
(这里前后端是一样的,你出队的时候也是remob at most one node,所以你最多只能free 1 node。)