调试遗留代码。我有一个用 C 编写的程序。它实际上要长得多,但我创建了一个小的可重现程序来显示问题(请忽略这个程序没有多大意义的事实)。程序:
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <malloc.h>
#include <ctype.h>
#include <glib.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#define FILE_SEP "/"
#define LENGTH 10
FILE *log_file;
char TMP[LENGTH];
char RESULT_DIRECTORY[LENGTH + 12];
int open_log() {
GString *path = g_string_new(RESULT_DIRECTORY);
g_string_append(path, FILE_SEP);
g_string_append(path, TMP);
g_string_append(path,".usr");
log_file = fopen(path->str,"w");
if (!log_file)
return 1;
return 0;
}
void close_log() {
fclose(log_file);
}
int main(int argc, char *argv[]) {
strcpy(TMP, "tmp");
strcpy(RESULT_DIRECTORY, "/home/");
if (open_log()) {
return 1;
}
close_log();
return 0;
}
运行 valgrind 我得到:
> valgrind --tool=memcheck --track-origins=yes --leak-check=full --show-reachable=yes program
==84011== Memcheck, a memory error detector
==84011== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==84011== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==84011== Command: c_status_reader
==84011==
==84011==
==84011== HEAP SUMMARY:
==84011== in use at exit: 5,292 bytes in 9 blocks
==84011== total heap usage: 10 allocs, 1 frees, 5,860 bytes allocated
==84011==
==84011== 16 bytes in 1 blocks are possibly lost in loss record 1 of 7
==84011== at 0x4C29104: malloc (vg_replace_malloc.c:299)
==84011== by 0x4C29278: realloc (vg_replace_malloc.c:785)
==84011== by 0x5078ABD: g_realloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5092B13: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093C99: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x108BE0: open_log (program.c:21)
==84011== by 0x108A6E: main (program.c:40)
==84011==
==84011== 252 bytes in 1 blocks are still reachable in loss record 2 of 7
==84011== at 0x4C27393: calloc (vg_replace_malloc.c:711)
==84011== by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x508CCE2: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x508EB5C: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x108BE0: open_log (program.c:21)
==84011== by 0x108A6E: main (program.c:40)
==84011==
==84011== 496 bytes in 1 blocks are possibly lost in loss record 3 of 7
==84011== at 0x4C2710E: memalign (vg_replace_malloc.c:858)
==84011== by 0x4C271A9: posix_memalign (vg_replace_malloc.c:1021)
==84011== by 0x508D4B0: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x508ECE2: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x108BE0: open_log (program.c:21)
==84011== by 0x108A6E: main (program.c:40)
==84011==
==84011== 504 bytes in 1 blocks are still reachable in loss record 4 of 7
==84011== at 0x4C27393: calloc (vg_replace_malloc.c:711)
==84011== by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x508CCC3: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x508EB5C: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x108BE0: open_log (program.c:21)
==84011== by 0x108A6E: main (program.c:40)
==84011==
==84011== 504 bytes in 1 blocks are still reachable in loss record 5 of 7
==84011== at 0x4C27393: calloc (vg_replace_malloc.c:711)
==84011== by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x508CD2A: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x508EB5C: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x108BE0: open_log (program.c:21)
==84011== by 0x108A6E: main (program.c:40)
==84011==
==84011== 1,488 bytes in 3 blocks are possibly lost in loss record 6 of 7
==84011== at 0x4C2710E: memalign (vg_replace_malloc.c:858)
==84011== by 0x4C271A9: posix_memalign (vg_replace_malloc.c:1021)
==84011== by 0x508D4B0: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x508ED22: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x108BE0: open_log (program.c:21)
==84011== by 0x108A6E: main (program.c:40)
==84011==
==84011== 2,032 bytes in 1 blocks are still reachable in loss record 7 of 7
==84011== at 0x4C27393: calloc (vg_replace_malloc.c:711)
==84011== by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x508EB12: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==84011== by 0x108BE0: open_log (program.c:21)
==84011== by 0x108A6E: main (program.c:40)
==84011==
==84011== LEAK SUMMARY:
==84011== definitely lost: 0 bytes in 0 blocks
==84011== indirectly lost: 0 bytes in 0 blocks
==84011== possibly lost: 2,000 bytes in 5 blocks
==84011== still reachable: 3,292 bytes in 4 blocks
==84011== suppressed: 0 bytes in 0 blocks
==84011==
==84011== For counts of detected and suppressed errors, rerun with: -v
==84011== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 6 from 5)
我认为我理解这个问题 - 它在某处缺少 g_string_free
调用。但是,当我实际使用它时,它说:仍然可达:8 个 block 中的 5,276 字节
。例如,我只有以下 open_log
(并且没有调用 close_log
):
int open_log() {
GString *path = g_string_new(RESULT_DIRECTORY);
g_string_append(path, FILE_SEP);
g_string_free(path,TRUE);
//log_file = fopen(path->str,"w");
//if (!log_file)
// return 1;
return 0;
}
我得到:
==88254==
==88254== LEAK SUMMARY:
==88254== definitely lost: 0 bytes in 0 blocks
==88254== indirectly lost: 0 bytes in 0 blocks
==88254== possibly lost: 0 bytes in 0 blocks
==88254== still reachable: 5,276 bytes in 8 blocks
==88254== suppressed: 0 bytes in 0 blocks
但是,如果我删除 g_string_append(path, FILE_SEP);
那么它实际上可以工作!所以我猜测,当我执行 g_string_free
时,它只会删除初始字符串 path
而不是附加部分。这是对的吗?我该如何解决这些问题?
编辑:
实际上,我尝试的第一个想法是在 fopen
之后添加 g_string_free(path, TRUE);
,但我仍然看到内存泄漏。代码:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdio.h>
#include<string.h>
#include<malloc.h>
#include<ctype.h>
#include<glib.h>
#include<stdlib.h>
#define FILE_SEP "/"
#define LENGTH 10
FILE *log_file;
char TMP[LENGTH];
char RESULT_DIRECTORY[LENGTH + 12];
int open_log(void) {
GString *path = g_string_new(RESULT_DIRECTORY);
g_string_append(path, FILE_SEP);
g_string_append(path, TMP);
g_string_append(path, ".usr");
log_file = fopen(path->str, "w");
g_string_free(path, TRUE);
if (!log_file)
return 1;
return 0;
}
void close_log() {
if (log_file) {
fclose(log_file);
log_file = NULL;
}
}
int main(int argc, char *argv[]) {
strcpy(TMP, "tmp");
strcpy(RESULT_DIRECTORY, "/home/");
if (open_log()) {
return 1;
}
close_log();
return 0;
}
valgrind 输出:
==23525== Memcheck, a memory error detector
==23525== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==23525== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==23525== Command: c_status_reader
==23525==
==23525==
==23525== HEAP SUMMARY:
==23525== in use at exit: 5,276 bytes in 8 blocks
==23525== total heap usage: 10 allocs, 2 frees, 5,860 bytes allocated
==23525==
==23525== 252 bytes in 1 blocks are still reachable in loss record 1 of 6
==23525== at 0x4C27393: calloc (vg_replace_malloc.c:711)
==23525== by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x508CCE2: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x508EB5C: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x108C31: open_log (program.c:21)
==23525== by 0x108ABC: main (program.c:45)
==23525==
==23525== 496 bytes in 1 blocks are still reachable in loss record 2 of 6
==23525== at 0x4C2710E: memalign (vg_replace_malloc.c:858)
==23525== by 0x4C271A9: posix_memalign (vg_replace_malloc.c:1021)
==23525== by 0x508D4B0: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x508ECE2: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x108C31: open_log (program.c:21)
==23525== by 0x108ABC: main (program.c:45)
==23525==
==23525== 504 bytes in 1 blocks are still reachable in loss record 3 of 6
==23525== at 0x4C27393: calloc (vg_replace_malloc.c:711)
==23525== by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x508CCC3: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x508EB5C: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x108C31: open_log (program.c:21)
==23525== by 0x108ABC: main (program.c:45)
==23525==
==23525== 504 bytes in 1 blocks are still reachable in loss record 4 of 6
==23525== at 0x4C27393: calloc (vg_replace_malloc.c:711)
==23525== by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x508CD2A: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x508EB5C: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x108C31: open_log (program.c:21)
==23525== by 0x108ABC: main (program.c:45)
==23525==
==23525== 1,488 bytes in 3 blocks are still reachable in loss record 5 of 6
==23525== at 0x4C2710E: memalign (vg_replace_malloc.c:858)
==23525== by 0x4C271A9: posix_memalign (vg_replace_malloc.c:1021)
==23525== by 0x508D4B0: ??? (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x508ED22: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x108C31: open_log (program.c:21)
==23525== by 0x108ABC: main (program.c:45)
==23525==
==23525== 2,032 bytes in 1 blocks are still reachable in loss record 6 of 6
==23525== at 0x4C27393: calloc (vg_replace_malloc.c:711)
==23525== by 0x5078B39: g_malloc0 (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x508EB12: g_slice_alloc (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x5093C6A: g_string_sized_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x5093D14: g_string_new (in /usr/lib64/libglib-2.0.so.0.2200.5)
==23525== by 0x108C31: open_log (program.c:21)
==23525== by 0x108ABC: main (program.c:45)
==23525==
==23525== LEAK SUMMARY:
==23525== definitely lost: 0 bytes in 0 blocks
==23525== indirectly lost: 0 bytes in 0 blocks
==23525== possibly lost: 0 bytes in 0 blocks
==23525== still reachable: 5,276 bytes in 8 blocks
==23525== suppressed: 0 bytes in 0 blocks
==23525==
==23525== For counts of detected and suppressed errors, rerun with: -v
==23525== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 5)
为什么没有解决?我什至尝试将 path
设置为全局变量,并在 close_log
函数中调用 g_string_free
。但没有成功。
最佳答案
您的第一个假设是正确的,您既没有在 open_log
中也没有在 close_log
中调用 g_string_free
,因此会出现内存泄漏。
至于
But, when I actually use it, it says:
still reachable: 5,276 bytes in 8 blocks.
. For example I have only the followingopen_log
(and without callingclose_log
):
引文中的最后一句话就是答案。您没有调用 close_log
,因此 FILE *log_file
现在泄漏。
if I remove
g_string_append(path, FILE_SEP);
then it actually works!
如果删除 g_string_append
,则 log_file = fopen(path->str,"w");
无法打开文件,因为它是目录,fopen
返回 NULL
并且没有任何泄漏。
如果在所有修复后仍然出现内存泄漏,那么您会看到 valgrind 关于 glib 内部内容的误报。 glib 开发人员非常友善,他们提供了特殊文件来抑制 valgrinds 中的此类误报:
/usr/share/glib-2.0/valgrind/glib.supp
此路径可能会有所不同,查找glib.supp
,使用命令locate valgrind/glib.supp
。将文件与 valgrind 一起使用:
valgrind --suppressions=/usr/share/glib-2.0/valgrind/glib.supp <...>
关于c - 打开和关闭日志文件会导致 C 中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71550326/