为什么 valgrind 仅通过 运行 程序多次报告不同的结果(没有泄漏是可能的/仍然可以达到)?

Why does valgrind report different results (no leaks are possible / still reachable) just by running the program multiple times?

在调试 运行dom 分段错误时,我 运行 valgrind,运行 多次使用同一个程序我得到不同的结果。这是该程序的简化版本(我在这个简化版本上没有遇到 运行dom 分段错误):

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

pthread_t* tid;
pthread_t prodId;
int numberThreads = 0;

void *worker(void *arg);
void *producer(void *arg);

int main(int argc, char** argv) {
    numberThreads = atoi((char *) argv[1]);
    tid = (pthread_t*) malloc(sizeof (pthread_t) * numberThreads);
    pthread_create(&prodId, NULL, producer, &prodId);
    pthread_join(prodId, NULL);
    free(tid);
    return (EXIT_SUCCESS);
}

void *producer(void *arg) {
    for (int x = 0; x < numberThreads; x++)
        pthread_create(&(tid[x]), NULL, worker, &(tid[x]));
    for (int x = 0; x < numberThreads; x++)
        pthread_join(tid[x], NULL);
    pthread_exit(NULL);
}

void *worker(void *arg) {
    pthread_exit(NULL);
}

这里是运行程序连续几次的输出:

$ valgrind --leak-check=full --leak-check=full --show-leak-kinds=all  ./memleek 1
==3044== Memcheck, a memory error detector
==3044== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3044== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==3044== Command: ./memleek 1
==3044== 
==3044== 
==3044== HEAP SUMMARY:
==3044==     in use at exit: 0 bytes in 0 blocks
==3044==   total heap usage: 8 allocs, 8 frees, 2,222 bytes allocated
==3044== 
==3044== All heap blocks were freed -- no leaks are possible
==3044== 
==3044== For counts of detected and suppressed errors, rerun with: -v
==3044== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
$ 
$ 
$ valgrind --leak-check=full --leak-check=full --show-leak-kinds=all  ./memleek 2
==3047== Memcheck, a memory error detector
==3047== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3047== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==3047== Command: ./memleek 2
==3047== 
==3047== 
==3047== HEAP SUMMARY:
==3047==     in use at exit: 0 bytes in 0 blocks
==3047==   total heap usage: 9 allocs, 9 frees, 2,502 bytes allocated
==3047== 
==3047== All heap blocks were freed -- no leaks are possible
==3047== 
==3047== For counts of detected and suppressed errors, rerun with: -v
==3047== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
$
$
$ valgrind --leak-check=full --leak-check=full --show-leak-kinds=all  ./memleek 2
==3051== Memcheck, a memory error detector
==3051== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3051== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==3051== Command: ./memleek 2
==3051== 
==3051== 
==3051== HEAP SUMMARY:
==3051==     in use at exit: 0 bytes in 0 blocks
==3051==   total heap usage: 9 allocs, 9 frees, 2,502 bytes allocated
==3051== 
==3051== All heap blocks were freed -- no leaks are possible
==3051== 
==3051== For counts of detected and suppressed errors, rerun with: -v
==3051== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
$
$
$ valgrind --leak-check=full --leak-check=full --show-leak-kinds=all  ./memleek 2
==3055== Memcheck, a memory error detector
==3055== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3055== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==3055== Command: ./memleek 2
==3055== 
==3055== 
==3055== HEAP SUMMARY:
==3055==     in use at exit: 1,614 bytes in 4 blocks
==3055==   total heap usage: 9 allocs, 5 frees, 2,502 bytes allocated
==3055== 
==3055== 36 bytes in 1 blocks are still reachable in loss record 1 of 4
==3055==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==3055==    by 0x401AE89: strdup (strdup.c:42)
==3055==    by 0x4016676: _dl_load_cache_lookup (dl-cache.c:311)
==3055==    by 0x4008A87: _dl_map_object (dl-load.c:2336)
==3055==    by 0x4013B13: dl_open_worker (dl-open.c:237)
==3055==    by 0x400F643: _dl_catch_error (dl-error.c:187)
==3055==    by 0x4013608: _dl_open (dl-open.c:660)
==3055==    by 0x517431C: do_dlopen (dl-libc.c:87)
==3055==    by 0x400F643: _dl_catch_error (dl-error.c:187)
==3055==    by 0x51743AE: dlerror_run (dl-libc.c:46)
==3055==    by 0x5174421: __libc_dlopen_mode (dl-libc.c:163)
==3055==    by 0x4E4966A: pthread_cancel_init (unwind-forcedunwind.c:52)
==3055== 
==3055== 36 bytes in 1 blocks are still reachable in loss record 2 of 4
==3055==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==3055==    by 0x400B4D3: _dl_new_object (dl-object.c:165)
==3055==    by 0x400587C: _dl_map_object_from_fd (dl-load.c:1000)
==3055==    by 0x400874B: _dl_map_object (dl-load.c:2470)
==3055==    by 0x4013B13: dl_open_worker (dl-open.c:237)
==3055==    by 0x400F643: _dl_catch_error (dl-error.c:187)
==3055==    by 0x4013608: _dl_open (dl-open.c:660)
==3055==    by 0x517431C: do_dlopen (dl-libc.c:87)
==3055==    by 0x400F643: _dl_catch_error (dl-error.c:187)
==3055==    by 0x51743AE: dlerror_run (dl-libc.c:46)
==3055==    by 0x5174421: __libc_dlopen_mode (dl-libc.c:163)
==3055==    by 0x4E4966A: pthread_cancel_init (unwind-forcedunwind.c:52)
==3055== 
==3055== 360 bytes in 1 blocks are still reachable in loss record 3 of 4
==3055==    at 0x4C2DBC5: calloc (vg_replace_malloc.c:711)
==3055==    by 0x4010FBD: _dl_check_map_versions (dl-version.c:293)
==3055==    by 0x4014076: dl_open_worker (dl-open.c:286)
==3055==    by 0x400F643: _dl_catch_error (dl-error.c:187)
==3055==    by 0x4013608: _dl_open (dl-open.c:660)
==3055==    by 0x517431C: do_dlopen (dl-libc.c:87)
==3055==    by 0x400F643: _dl_catch_error (dl-error.c:187)
==3055==    by 0x51743AE: dlerror_run (dl-libc.c:46)
==3055==    by 0x5174421: __libc_dlopen_mode (dl-libc.c:163)
==3055==    by 0x4E4966A: pthread_cancel_init (unwind-forcedunwind.c:52)
==3055==    by 0x4E49853: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)
==3055==    by 0x4E47D7F: __pthread_unwind (unwind.c:121)
==3055== 
==3055== 1,182 bytes in 1 blocks are still reachable in loss record 4 of 4
==3055==    at 0x4C2DBC5: calloc (vg_replace_malloc.c:711)
==3055==    by 0x400B215: _dl_new_object (dl-object.c:75)
==3055==    by 0x400587C: _dl_map_object_from_fd (dl-load.c:1000)
==3055==    by 0x400874B: _dl_map_object (dl-load.c:2470)
==3055==    by 0x4013B13: dl_open_worker (dl-open.c:237)
==3055==    by 0x400F643: _dl_catch_error (dl-error.c:187)
==3055==    by 0x4013608: _dl_open (dl-open.c:660)
==3055==    by 0x517431C: do_dlopen (dl-libc.c:87)
==3055==    by 0x400F643: _dl_catch_error (dl-error.c:187)
==3055==    by 0x51743AE: dlerror_run (dl-libc.c:46)
==3055==    by 0x5174421: __libc_dlopen_mode (dl-libc.c:163)
==3055==    by 0x4E4966A: pthread_cancel_init (unwind-forcedunwind.c:52)
==3055== 
==3055== LEAK SUMMARY:
==3055==    definitely lost: 0 bytes in 0 blocks
==3055==    indirectly lost: 0 bytes in 0 blocks
==3055==      possibly lost: 0 bytes in 0 blocks
==3055==    still reachable: 1,614 bytes in 4 blocks
==3055==         suppressed: 0 bytes in 0 blocks
==3055== 
==3055== For counts of detected and suppressed errors, rerun with: -v
==3055== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
$ 

我注意到,如果我 运行 4 个工人,通过将 4 作为第一个参数传递,它会不断显示

still reachable: 1,614 bytes in 4 blocks

考虑到根据 this,Valgrind 泄漏报告中的 "still reachable" 类别指的是仅适合 "memory leak" 的第一个定义的分配。这些块没有被释放,但它们本可以被释放(如果程序员愿意的话),因为程序仍在跟踪指向这些内存块的指针。

好吧,我想释放这些块。谁能告诉我怎么做?谢谢!

我试过 运行 你的程序,我看到了相同的行为。我还发现删除一行,即工人中的 pthread_exit,删除了有关仍可访问内存的 valgrind 警告。

我开始怀疑glibc,这被一个类似的SO证实了question/answer: glibc oddity with Valgrind