heapusage 检测到可能由 printf 引起的内存泄漏
heapusage detects Memory leak possibly caused by printf
我正在用 C 语言的链表实现一个优先级队列,但是当我打印出 pop
操作时出现内存泄漏。我还有另一个内存泄漏问题,我也在努力寻找它。
作为旁注,我使用 heapusage
by d99kris
而不是 Valgrind
。
这是我使用printf
时的堆摘要:
HEAP SUMMARY:
in use at exit: 4112 bytes in 2 blocks
total heap usage: 10 allocs, 17 frees, 4536 bytes allocated
peak heap usage: 4256 bytes allocated
16 bytes in 1 block(s) are lost, originally allocated at:
LEAK SUMMARY:
definitely lost: 4112 bytes in 2 blocks
这是没有printf
的堆摘要:
HEAP SUMMARY:
in use at exit: 16 bytes in 1 blocks
total heap usage: 9 allocs, 10 frees, 440 bytes allocated
peak heap usage: 256 bytes allocated
LEAK SUMMARY:
definitely lost: 16 bytes in 1 blocks
我的pop
函数:
void *prio_q_pop(struct prio_q *q) {
q->size--;
struct elem *temp = q->first;
(q->first) = (q->first)->next;
void *asd = temp->datei;
free(temp);
return asd;
}
还有我的 main
函数,我调用 printf
struct prio_q *queue;
char *s;
int i;
queue = prio_q_create();
push(queue, "Bye World", 0);
for (i = 0; i < 5; i++) {
s = prio_q_pop(queue);
//printf("%s\n", s);
}
s = prio_q_front(queue);
//printf("%s\n", s);
reason
问题不是由 my 代码引起的,它是内存检查器。以下程序泄漏了 1 个块,堆使用了 2 次分配和 4 次释放。
#include <stdio.h>
int main() {
printf("omer");
return 0;
}
这是误报。如果有的话,问题是 heapusage 没有足够好的文档。我建议使用更好的泄漏检查器,如泄漏消毒剂或 Valgrind。
我创建了一个文件 test.c
。
#include <stdio.h>
int main(int argc, char **argv) {
puts("Hello, world!");
}
使用泄漏消毒剂,没有错误。
$ cc -fsanitize=leak -g test.c
$ ./a.out
Hello, world!
使用地址清理器,没有错误。
$ cc -fsanitize=address -g test.c
$ ./a.out
Hello, world!
使用 Valgrind,没有错误。
$ cc -g test.c
$ valgrind ./a.out
==189174== Memcheck, a memory error detector
==189174== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==189174== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==189174== Command: ./a.out
==189174==
Hello, world!
==189174==
==189174== HEAP SUMMARY:
==189174== in use at exit: 0 bytes in 0 blocks
==189174== total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
==189174==
==189174== All heap blocks were freed -- no leaks are possible
==189174==
==189174== For counts of detected and suppressed errors, rerun with: -v
==189174== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
使用heapusage,泄漏!
$ cc -g test.c
$ ./heapusage ./a.out
Hello, world!
==189005== Heapusage - https://github.com/d99kris/heapusage
==189005==
==189005== HEAP SUMMARY:
==189005== in use at exit: 1024 bytes in 1 blocks
==189005== total heap usage: 1 allocs, 0 frees, 1024 bytes allocated
==189005== peak heap usage: 1024 bytes allocated
==189005==
==189005== 1024 bytes in 1 block(s) are lost, originally allocated at:
==189005== at 0x00007f99f0de56a7: malloc + 49
==189005== at 0x00007f99f0a96a32: _IO_file_doallocate + 114
==189005== at 0x00007f99f0aa4a46: _IO_doallocbuf + 70
==189005== at 0x00007f99f0aa3da8: _IO_file_overflow + 472
==189005== at 0x00007f99f0aa2e86: _IO_file_xsputn + 182
==189005== at 0x00007f99f0a99033: _IO_puts + 211
==189005== at 0x000055f667ee7655:
==189005== at 0x00007f99f0a502b1: __libc_start_main + 241
==189005== at 0x000055f667ee755a:
==189005==
==189005== LEAK SUMMARY:
==189005== definitely lost: 1024 bytes in 1 blocks
==189005==
分析
Heapusage 通过挂钩 malloc 和 free 来工作(并且不扫描内存中的指针)。 Heapusage 没有在文档中完整解释这种方法的优点或缺点。优点是速度快,缺点是不精确
特别是,我认为 heapusage 给出的信息不正确:"definitely lost" 一词不适用于此处!
如果您想要更好的错误消息,请使用上面推荐的工具之一:泄漏消毒剂或 Valgrind (memcheck)。
总的来说,我还想提醒人们,误报是使用此类工具的常态。程序是否"Valgrind clean"与程序是否正确是不同的问题。
与 Valgrind 不同,heapusage
不会跟踪 C 库为其自身目的分配的内存。 printf
间接导致此问题,因为流 stdout
是行缓冲到终端并完全缓冲到文件。仅当您实际产生输出时才分配流缓冲区(通过 printf
或任何其他输出函数)。
您可以尝试通过在 main
函数开始时使 stdout
无缓冲来解决此限制。例如试试这个:
#include <stdio.h>
int main() {
setvbuf(stdout, NULL, _IONBF, 0);
printf("omer\n");
return 0;
}
如果以上代码仍然显示泄漏,请尝试以下替代方法:
#include <stdio.h>
int main() {
char buf[BUFSIZ];
setvbuf(stdout, buf, _IONBF, BUFSIZ);
printf("omer\n");
fclose(stdout);
return 0;
}
另请注意,从 stdin
读取输入也会为输入流分配一个缓冲区。程序打开的任何其他流都应该在离开 main()
函数之前关闭。关闭流会释放在后台为其分配的所有内存。
我正在用 C 语言的链表实现一个优先级队列,但是当我打印出 pop
操作时出现内存泄漏。我还有另一个内存泄漏问题,我也在努力寻找它。
作为旁注,我使用 heapusage
by d99kris
而不是 Valgrind
。
这是我使用printf
时的堆摘要:
HEAP SUMMARY:
in use at exit: 4112 bytes in 2 blocks
total heap usage: 10 allocs, 17 frees, 4536 bytes allocated
peak heap usage: 4256 bytes allocated
16 bytes in 1 block(s) are lost, originally allocated at:
LEAK SUMMARY:
definitely lost: 4112 bytes in 2 blocks
这是没有printf
的堆摘要:
HEAP SUMMARY:
in use at exit: 16 bytes in 1 blocks
total heap usage: 9 allocs, 10 frees, 440 bytes allocated
peak heap usage: 256 bytes allocated
LEAK SUMMARY:
definitely lost: 16 bytes in 1 blocks
我的pop
函数:
void *prio_q_pop(struct prio_q *q) {
q->size--;
struct elem *temp = q->first;
(q->first) = (q->first)->next;
void *asd = temp->datei;
free(temp);
return asd;
}
还有我的 main
函数,我调用 printf
struct prio_q *queue;
char *s;
int i;
queue = prio_q_create();
push(queue, "Bye World", 0);
for (i = 0; i < 5; i++) {
s = prio_q_pop(queue);
//printf("%s\n", s);
}
s = prio_q_front(queue);
//printf("%s\n", s);
reason
问题不是由 my 代码引起的,它是内存检查器。以下程序泄漏了 1 个块,堆使用了 2 次分配和 4 次释放。
#include <stdio.h>
int main() {
printf("omer");
return 0;
}
这是误报。如果有的话,问题是 heapusage 没有足够好的文档。我建议使用更好的泄漏检查器,如泄漏消毒剂或 Valgrind。
我创建了一个文件 test.c
。
#include <stdio.h>
int main(int argc, char **argv) {
puts("Hello, world!");
}
使用泄漏消毒剂,没有错误。
$ cc -fsanitize=leak -g test.c $ ./a.out Hello, world!
使用地址清理器,没有错误。
$ cc -fsanitize=address -g test.c $ ./a.out Hello, world!
使用 Valgrind,没有错误。
$ cc -g test.c $ valgrind ./a.out ==189174== Memcheck, a memory error detector ==189174== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==189174== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info ==189174== Command: ./a.out ==189174== Hello, world! ==189174== ==189174== HEAP SUMMARY: ==189174== in use at exit: 0 bytes in 0 blocks ==189174== total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated ==189174== ==189174== All heap blocks were freed -- no leaks are possible ==189174== ==189174== For counts of detected and suppressed errors, rerun with: -v ==189174== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
使用heapusage,泄漏!
$ cc -g test.c $ ./heapusage ./a.out Hello, world! ==189005== Heapusage - https://github.com/d99kris/heapusage ==189005== ==189005== HEAP SUMMARY: ==189005== in use at exit: 1024 bytes in 1 blocks ==189005== total heap usage: 1 allocs, 0 frees, 1024 bytes allocated ==189005== peak heap usage: 1024 bytes allocated ==189005== ==189005== 1024 bytes in 1 block(s) are lost, originally allocated at: ==189005== at 0x00007f99f0de56a7: malloc + 49 ==189005== at 0x00007f99f0a96a32: _IO_file_doallocate + 114 ==189005== at 0x00007f99f0aa4a46: _IO_doallocbuf + 70 ==189005== at 0x00007f99f0aa3da8: _IO_file_overflow + 472 ==189005== at 0x00007f99f0aa2e86: _IO_file_xsputn + 182 ==189005== at 0x00007f99f0a99033: _IO_puts + 211 ==189005== at 0x000055f667ee7655: ==189005== at 0x00007f99f0a502b1: __libc_start_main + 241 ==189005== at 0x000055f667ee755a: ==189005== ==189005== LEAK SUMMARY: ==189005== definitely lost: 1024 bytes in 1 blocks ==189005==
分析
Heapusage 通过挂钩 malloc 和 free 来工作(并且不扫描内存中的指针)。 Heapusage 没有在文档中完整解释这种方法的优点或缺点。优点是速度快,缺点是不精确
特别是,我认为 heapusage 给出的信息不正确:"definitely lost" 一词不适用于此处!
如果您想要更好的错误消息,请使用上面推荐的工具之一:泄漏消毒剂或 Valgrind (memcheck)。
总的来说,我还想提醒人们,误报是使用此类工具的常态。程序是否"Valgrind clean"与程序是否正确是不同的问题。
与 Valgrind 不同,heapusage
不会跟踪 C 库为其自身目的分配的内存。 printf
间接导致此问题,因为流 stdout
是行缓冲到终端并完全缓冲到文件。仅当您实际产生输出时才分配流缓冲区(通过 printf
或任何其他输出函数)。
您可以尝试通过在 main
函数开始时使 stdout
无缓冲来解决此限制。例如试试这个:
#include <stdio.h>
int main() {
setvbuf(stdout, NULL, _IONBF, 0);
printf("omer\n");
return 0;
}
如果以上代码仍然显示泄漏,请尝试以下替代方法:
#include <stdio.h>
int main() {
char buf[BUFSIZ];
setvbuf(stdout, buf, _IONBF, BUFSIZ);
printf("omer\n");
fclose(stdout);
return 0;
}
另请注意,从 stdin
读取输入也会为输入流分配一个缓冲区。程序打开的任何其他流都应该在离开 main()
函数之前关闭。关闭流会释放在后台为其分配的所有内存。