You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 15:45:10