C语言still reachable内存泄漏:是否为业务代码问题及修复咨询
问题
检测到一处472字节的still reachable内存泄漏,Valgrind提示泄漏位于__fopen_internal函数,调用栈指向自定义函数create_log_process(logger.c:41)。业务代码中未手动调用malloc,现咨询:
- 该泄漏是否源于我的自定义代码?
- 若是,该如何修复?
- 是否需要关闭打开的文件或释放内存?
Valgrind检测输出
472 bytes in 1 blocks are still reachable in loss record 1 of 1 ==192077== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==192077== by 0x48EF92D: __fopen_internal (iofopen.c:65) ==192077== by 0x48EF92D: fopen@@GLIBC_2.2.5 (iofopen.c:86) ==192077== by 0x10974E: create_log_process (logger.c:41) ==192077== by 0x1094ED: open_db (sensor_db.c:21) ==192077== by 0x1093C5: main (main.c:15) ==192077== ==192077== LEAK SUMMARY: ==192077== definitely lost: 0 bytes in 0 blocks ==192077== indirectly lost: 0 bytes in 0 blocks ==192077== possibly lost: 0 bytes in 0 blocks ==192077== still reachable: 472 bytes in 1 blocks ==192077== suppressed: 0 bytes in 0 blocks
对应函数代码
int create_log_process() { // log file opening fp = fopen("gateway.log", "a"); if (fp == NULL) { perror("Error occurred during log file opening"); exit(1); } // creation of communication and child process if (pipe(fd) == -1) { perror("Error occurred during pipe creation"); fclose(fp); exit(5); }; pid = fork(); // error handle if (pid == -1) { perror("fork failed"); close(fd[0]); close(fd[1]); fclose(fp); exit(2); } else if (pid == 0) { close(fd[1]); // closing write_end. char received_message[BUFFER_SIZE]; size_t message_length; while(read(fd[0], &message_length, sizeof(size_t)) > 0) { if ((read(fd[0], received_message, message_length)) < 0) { perror("An error occurred during reading from pipe"); fclose(fp); close(fd[0]); exit(7); } printf("child process reads: %s \n", received_message); // timestamp creation. time_t timer; time(&timer); struct tm *timestamp_info; timestamp_info = localtime(&timer); char timestamp[20]; strftime(timestamp, sizeof(timestamp), "%a %b %d %X %Y", timestamp_info); // writing message to log file. if (fprintf(fp, "%d - %s - %s\n", i++, timestamp, received_message) < 0) { perror("Error occurred during writing to log file"); fclose(fp); close(fd[0]); exit(6); // error during writing to file } fflush(fp); // helps writing to log file without data to be buffered first. } // fclose(fp); close(fd[0]); exit(0); // success status. } else { close(fd[0]); } return 0; }
注:代码中未手动调用malloc。
解答
1. 泄漏是否源于自定义代码?
是。虽然你没手动调用malloc,但fopen内部会调用malloc分配内存维护文件流(包括FILE结构体和相关缓冲区)。Valgrind调用栈明确指向你在create_log_process中调用的fopen,且代码存在文件未正确关闭的情况,导致这部分内存未被释放,因此泄漏源于你的自定义代码。
2. 如何修复?
需要修正两处文件流未关闭的问题:
- 子进程分支:取消注释
fclose(fp),确保while循环结束后关闭文件流 - 父进程分支:添加
fclose(fp),关闭父进程中打开的文件流
修改后的关键代码片段:
// 子进程部分 } fclose(fp); // 取消注释该行 close(fd[0]); exit(0); // success status. } else { close(fd[0]); fclose(fp); // 父进程添加该行,关闭文件流 }
3. 是否需要关闭打开的文件或释放内存?
需要关闭打开的文件。fopen分配的内存会在调用fclose时由标准库自动释放,无需手动调用free。只要确保所有打开文件流的分支(父、子进程)都调用fclose,就能消除这个still reachable的内存泄漏。
补充:still reachable类型的内存泄漏指程序退出时仍可访问但未释放的内存,系统会在进程结束后自动回收,但从规范编程角度,主动关闭所有资源是良好习惯,能避免这类检测报告。
内容的提问来源于stack exchange,提问作者dsdfs
相关产品推荐
相关产品推荐

