此块中提到的所有函数都是库函数。如何纠正这种内存泄漏?
它列在“ 仍然可达 ”类别下。(还有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 已被移植来执行此操作的所有平台)。