C Valgrind检测到仍然可以到达的泄漏
此块中提到的所有函数都是库函数。如何更正此内存泄漏 它列在“仍然可以访问”类别下。(还有4个,非常相似,但大小不一) 捕获:一旦我运行了我的程序,它就没有内存泄漏,但在Valgrind输出中有一行额外的内容,这是以前没有的: 丢弃0x5296fa0-0x52af438处的符号 in/lib/libgcc_-4.4.4-20100630.so.1 由于munmap() 如果泄漏无法纠正,至少有人能解释为什么munmap()行导致Valgrind报告0“仍然可以到达”泄漏吗 编辑: 这是一个最小的测试样本:C Valgrind检测到仍然可以到达的泄漏,c,pthreads,valgrind,C,Pthreads,Valgrind,此块中提到的所有函数都是库函数。如何更正此内存泄漏 它列在“仍然可以访问”类别下。(还有4个,非常相似,但大小不一) 捕获:一旦我运行了我的程序,它就没有内存泄漏,但在Valgrind输出中有一行额外的内容,这是以前没有的: 丢弃0x5296fa0-0x52af438处的符号 in/lib/libgcc_-4.4.4-20100630.so.1 由于munmap() 如果泄漏无法纠正,至少有人能解释为什么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);
}
您似乎不明白什么是仍然可以访问的
意思
任何仍然可以到达的
都不是泄漏。您不需要对此做任何事情。因为底部有一些来自pthread家族的例程(但我不知道是哪一个),我猜您已经启动了一些线程作为可连接线程,并终止了执行
在调用pthread\u join
之前,该线程的退出状态信息一直可用。因此,在程序终止时,内存保存在丢失记录中,但它仍然可以访问,因为您可以使用pthread\u 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位)定义“内存泄漏”的方法不止一种。特别是,“内存泄漏”有两个主要定义,在程序员中很常见
“内存泄漏”的第一个常用定义是“在程序终止之前分配内存,但随后没有释放内存”。然而,许多程序员(正确地)认为,符合此定义的某些类型的内存泄漏实际上不会造成任何问题,因此不应被视为真正的“内存泄漏”
“内存泄漏”的一个可能更严格(也更有用)的定义是,“内存已分配,并且无法随后释放,因为程序不再有指向已分配内存块的指针。”换句话说,您无法释放不再有指向该块指针的内存。因此,这种内存是“内存泄漏”。Valgrind对“内存泄漏”一词使用了更严格的定义。这是一种可能导致大量堆耗尽的泄漏类型,特别是对于长寿命进程
Valgrind泄漏报告中的“仍然可访问”类别指的是仅符合“内存泄漏”第一个定义的分配。这些块没有被释放,但是它们可以被释放(如果程序员愿意的话),因为程序仍然在跟踪指向这些内存块的指针
一般来说,没有必要担心“仍然可以到达”的块。它们不会造成真正的内存泄漏可能导致的那种问题。例如,“仍然可到达”块通常不会导致堆耗尽。这是因为这些块通常是一次性分配的,在进程的整个生命周期中都会保留对它们的引用。虽然您可以检查并确保您的程序释放所有分配的内存,但这样做通常没有实际好处,因为无论如何,操作系统将在进程终止后回收所有进程的内存。与此形成对比的是真正的内存泄漏,如果不进行修复,可能会导致进程在运行足够长的时间后耗尽内存,或者只会导致进程消耗远远超过所需的内存
确保所有分配都具有匹配的“空闲”可能唯一有用的时间是泄漏检测工具无法判断哪些块“仍然可以访问”(但Valgrind可以做到这一点),或者操作系统没有回收终止进程的所有内存(Valgrind已移植用于此操作的所有平台).以下是对“仍然可以到达”的正确解释:
“仍然可到达”是指分配给全局和静态局部变量的泄漏。因为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”。对于未来的读者,“仍然可以访问”可能意味着您忘记关闭文件之类的内容。虽然在最初的问题中似乎不是这样,但你应该始终确保你已经这样做了。你能猜出munmap()是做什么使“仍然可以到达”的块消失的吗?@crypto:可能是卸载共享对象后调用了munmap
。共享对象使用的所有资源可能在卸载之前都已释放。这可以解释为什么在munmap
案例中“仍然可以到达”被释放。不过,我只是在猜测。这里没有足够的信息可以确定。在一种情况下,“仍然可以访问”的内存可以被视为内存泄漏:假设您
==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
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);
....
....
....
}