C语言 Valgrind检测到仍可触及的泄漏

odopli94  于 2023-08-03  发布在  其他
关注(0)|答案(5)|浏览(93)

本块中提到的所有函数都是库函数。如何纠正此内存泄漏?
列在“仍可访问”类别下。(还有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中0x 5296 fa 0 - 0x 52 af 438处的符号
如果泄漏不能被纠正,是否有人能至少解释一下为什么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

hzbexzde

hzbexzde1#

定义“内存泄漏”的方法不止一种。特别是,程序员通常使用的“内存泄漏”有两个主要定义。
第一个常用的“内存泄漏”的定义是,“内存被分配,并没有随后释放之前,程序终止。”然而,许多程序员(正确地)认为,某些类型的内存泄漏,符合这个定义实际上并不构成任何形式的问题,因此不应该被认为是 * 真正 *“内存泄漏”。
“内存泄漏”的一个更严格(也更有用)的定义是,“内存已分配,但 * 不能 * 随后释放,因为程序不再有指向已分配内存块的指针。”换句话说,您不能释放不再有任何指针指向的内存。因此,这样的存储器是“存储器泄漏”。Valgrind对术语“内存泄漏”使用了更严格的定义。这是一种可能导致严重的堆耗尽的泄漏类型,特别是对于长期存在的进程。
Valgrind的泄漏报告中的“仍然可访问”类别指的是仅符合“内存泄漏”的第一个定义的分配。这些块没有被释放,但是它们本来可以被释放(如果程序员愿意的话),因为程序仍然在跟踪指向这些内存块的指针。
一般来说,不需要担心“仍然可访问”的块。它们不会造成 true 内存泄漏可能导致的那种问题。例如,通常不存在来自“仍然可到达”块的堆耗尽的可能性。这是因为这些块通常是一次性分配,在进程的整个生存期内都会保留对这些块的引用。虽然你可以确保你的程序释放所有分配的内存,但这样做通常没有实际的好处,因为操作系统将在进程终止后回收所有的内存。与此相反,true 内存泄漏,如果不修复,可能会导致进程在运行足够长的时间后耗尽内存,或者只会导致进程消耗比必要的更多的内存。
可能只有当你的泄漏检测工具无法判断哪些块是“仍然可访问的”(但Valgrind可以做到这一点),或者你的操作系统没有回收所有终止进程的内存(所有Valgrind已经移植的平台都可以做到这一点)时,确保所有分配都有匹配的“空闲”才是有用的。

os8fio9y

os8fio9y2#

因为在底部有一些来自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-与您看到的很相似,我猜您看到的是一个已知问题,可以通过valgrind的抑制文件来解决。也许您的系统不是最新的,或者您的发行版没有维护这些东西。(我的是Ubuntu 10.4,64位)

f0ofjuux

f0ofjuux3#

以下是对“仍然可以访问”的正确解释:
“仍然可达”是指分配给全局和静态局部变量的泄漏。因为valgrind跟踪全局和静态变量,所以它可以排除那些“一次性”分配的内存。一个全局变量分配了一次分配,但从未重新分配过该分配,从它不会无限增长的意义上说,它通常不是“泄漏”。它仍然是一个严格意义上的泄漏,但通常可以忽略,除非你是迂腐的。
被分配了资源而没有释放的局部变量几乎总是泄漏的。
这里有一个例子

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

字符串
Valgrind将报告working_buf为“仍然可达-16 k”,temp_buf为“绝对丢失-5 k”。

dgtucam1

dgtucam14#

你似乎不明白still reachable是什么意思。
任何still reachable都不是泄漏。你不需要做任何事。

omqzjyyz

omqzjyyz5#

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

相关问题