繁体   English   中英

Valgrind 检测到仍可到达的泄漏

[英]Still Reachable Leak detected by Valgrind

本块中提到的所有函数都是库函数。 我怎样才能纠正这个内存泄漏?

它列在“仍然可达”类别下。 (还有4个,非常相似,但大小不同)

 630 bytes in 1 blocks are still reachable in loss record 5 of 5
    at 0x4004F1B: calloc (vg_replace_malloc.c:418)
    by 0x931CD2: _dl_new_object (dl-object.c:52)
    by 0x92DD36: _dl_map_object_from_fd (dl-load.c:972)
    by 0x92EFB6: _dl_map_object (dl-load.c:2251)
    by 0x939F1B: dl_open_worker (dl-open.c:255)
    by 0x935965: _dl_catch_error (dl-error.c:178)
    by 0x9399C5: _dl_open (dl-open.c:584)
    by 0xA64E31: do_dlopen (dl-libc.c:86)
    by 0x935965: _dl_catch_error (dl-error.c:178)
    by 0xA64FF4: __libc_dlopen_mode (dl-libc.c:47)
    by 0xAE6086: pthread_cancel_init (unwind-forcedunwind.c:53)
    by 0xAE61FC: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)

Catch:一旦我运行了我的程序,它就没有出现内存泄漏,但它在 Valgrind 输出中多了一行,这在以前是不存在的:

由于 munmap() 丢弃 /lib/libgcc_s-4.4.4-20100630.so.1 中 0x5296fa0-0x52af438 处的符号

如果泄漏无法纠正,至少有人可以解释为什么 munmap() 行会导致 Valgrind 报告 0 个“仍然可以访问”的泄漏?

编辑:

这是一个最小的测试样本:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *runner(void *param) {
    /* some operations ... */
    pthread_exit(NULL);
}

int n;

int main(void) {

    int i;
    pthread_t *threadIdArray;

    n=10; /* for example */

    threadIdArray = malloc((n+n-1)*sizeof(pthread_t));  

    for(i=0;i<(n+n-1);i++) {
        if( pthread_create(&threadIdArray[i],NULL,runner,NULL) != 0 ) {
            printf("Couldn't create thread %d\n",i);
            exit(1);
        }
    }


    for(i=0;i<(n+n-1);i++) {
        pthread_join(threadIdArray[i],NULL);
    }

    free(threadIdArray);

    return(0);
}

运行:

valgrind -v --leak-check=full --show-reachable=yes ./a.out

定义“内存泄漏”的方法不止一种。 特别是,“内存泄漏”有两个主要定义,在程序员中很常见。

“内存泄漏”的第一个常用定义是“内存已分配,但在程序终止之前并未随后释放”。 但是,许多程序员(正确地)争辩说,符合此定义的某些类型的内存泄漏实际上不会造成任何类型的问题,因此不应将其视为真正的“内存泄漏”。

“内存泄漏”的一个可以说更严格(也更有用)的定义是,“内存已分配,随后无法释放,因为程序不再有任何指向已分配内存块的指针。” 换句话说,您无法释放不再有任何指针指向的内存。 因此,这种内存是“内存泄漏”。 Valgrind 对术语“内存泄漏”使用了这个更严格的定义。 这种泄漏可能会导致显着的堆耗尽,尤其是对于长期存在的进程。

Valgrind 泄漏报告中的“仍然可达”类别是指仅符合“内存泄漏”的第一个定义的分配。 这些块没有被释放,但它们本来可以被释放(如果程序员想要的话),因为程序仍然在跟踪指向这些内存块的指针。

一般来说,不需要担心“仍然可达”的块。 它们不会造成真正的内存泄漏可能导致的那种问题。 例如,通常不会从“仍然可达”的块中耗尽堆。 这是因为这些块通常是一次性分配的,在进程的整个生命周期中都会保留对它们的引用。 虽然您可以通过并确保您的程序释放所有分配的内存,但这样做通常没有实际好处,因为操作系统将在进程终止后回收进程的所有内存,无论如何。 将此与真正的内存泄漏进行对比,如果不加以修复,如果保持运行时间足够长,可能会导致进程耗尽内存,或者只会导致进程消耗比所需更多的内存。

确保所有分配具有匹配的“释放”可能唯一有用的时候是如果您的泄漏检测工具无法判断哪些块“仍然可以访问”(但 Valgrind 可以做到这一点)或者如果您的操作系统没有回收所有终止进程的内存(Valgrind 已被移植来执行此操作的所有平台)。

由于底部有一些来自 pthread 家族的例程(但我不知道那个特定的例程),我猜你已经启动了一些线程作为可连接终止执行。

在您调用pthread_join之前,该线程的退出状态信息一直可用。 因此,内存在程序终止时保留在丢失记录中,但它仍然可以访问,因为您可以使用pthread_join来访问它。

如果这个分析是正确的,要么分离地启动这些线程,要么在终止程序之前加入它们。

编辑:我运行了您的示例程序(经过一些明显的更正后)并且我没有错误,但是以下内容

==18933== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
--18933-- 
--18933-- used_suppression:      2 dl-hack3-cond-1
--18933-- used_suppression:      2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a

由于dl- thing 与您看到的大部分内容相似,我猜您看到了一个已知问题,该问题在valgrind的抑制文件方面具有解决方案。 也许你的系统不是最新的,或者你的发行版没有维护这些东西。 (我的是 ubuntu 10.4,64 位)

这是“仍然可以访问”的正确解释:

“仍然可达”是分配给全局和静态局部变量的泄漏。 由于 valgrind 跟踪全局变量和静态变量,因此它可以排除分配“一劳永逸”的内存分配。 一个全局变量分配了一次分配并且从未重新分配该分配通常不是“泄漏”,因为它不会无限期地增长。 从严格意义上讲,它仍然是泄漏,但通常可以忽略,除非您迂腐。

分配了分配而不是释放的局部变量几乎总是泄漏。

这是一个例子

int foo(void)
{
    static char *working_buf = NULL;
    char *temp_buf;
    if (!working_buf) {
         working_buf = (char *) malloc(16 * 1024);
    }
    temp_buf = (char *) malloc(5 * 1024);

    ....
    ....
    ....

}

Valgrind 会将working_buf 报告为“仍可到达- 16k”,将temp_buf 报告为“肯定丢失- 5k”。

你似乎不明白什么是still reachable

任何still reachable东西都不是泄漏。 你不需要做任何事情。

对于未来的读者,“Still Reachable”可能意味着您忘记关闭文件之类的东西。 虽然在最初的问题中似乎不是这样,但你应该始终确保你已经这样做了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM