关于C#:为什么pthread导致内存泄漏

why pthread causes a memory leak

每当我创建pthread时,valgrind都会输出内存泄漏,

例如下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

void *timer1_function (void *eit){
  (void) eit;
    printf("hello world\
"
);
    pthread_exit(NULL);
}

int main(void){
   pthread_t timer1;
   pthread_create( &timer1, NULL, timer1_function,  NULL);  ///////line13
   int i=0;
   for(i=0;i<2;i++){usleep(1);}
   return 0;
}

valgrind输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
==1395== HEAP SUMMARY:
==1395==     in use at exit: 136 bytes in 1 blocks
==1395==   total heap usage: 6 allocs, 5 frees, 1,134 bytes allocated
==1395==
==1395== 136 bytes in 1 blocks are possibly lost in loss record 1 of 1
==1395==    at 0x402A629: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==1395==    by 0x4011304: allocate_dtv (dl-tls.c:297)
==1395==    by 0x4011AAB: _dl_allocate_tls (dl-tls.c:461)
==1395==    by 0x4052470: pthread_create@@GLIBC_2.1 (allocatestack.c:571)
==1395==    by 0x8048566: main (test.c:13)
==1395==
==1395== LEAK SUMMARY:
==1395==    definitely lost: 0 bytes in 0 blocks
==1395==    indirectly lost: 0 bytes in 0 blocks
==1395==      possibly lost: 136 bytes in 1 blocks
==1395==    still reachable: 0 bytes in 0 blocks
==1395==         suppressed: 0 bytes in 0 blocks

尽管我使用手册页作为参考,为什么pthread_create会引起问题,我该如何解决?


线程是分配的资源,您没有在退出之前释放它。您应该致电pthread_join;这也将消除您的骇客行为和不正确的睡眠循环的需要。

即使您修复了此问题,由于POSIX线程的某些实现(我猜您正在使用glibc / NPTL)缓存并重用线程资源而不是完全释放线程资源,所以valgrind仍然可能会出现"泄漏"。我不确定valgrind是否可以解决此问题。


我认为valgrind在退出程序时分析程序的状态,这很可能在线程完成执行之前:两微秒不足以将"Hello, world!\
"
写入控制台。将呼叫添加到pthread_join应该可以解决此泄漏:

1
pthread_join(timer1, NULL);


显示的泄漏与在子线程的本地存储(tls)中分配的DTV(动态线程矢量)结构有关。

在主线程(即产生子代的线程)中使用pthread_join()将确保修复泄漏。
对于不需要pthread_join()调用的用例,使用子pthread_t调用pthread_detach可确保释放内存。

来自pthread_detach的人:

The pthread_detach() function marks the thread identified by thread
as detached. When a detached thread terminates, its resources are
automatically released back to the system without the need for
another thread to join with the terminated thread.


当我无法调用pthread_join时,我看到了类似的结果。

当我调用pthread_join时,Valgrind将指示没有内存错误或泄漏。使用pthread_kill查看线程是否仍然存在,然后调用join清理和释放资源,得到了一个干净的结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int
stop_worker(worker_t *self)
{
    if (self) {
        // signal the thread to quit
            // (here using a variable and semaphore)
        self->thread_quit=TRUE;
        sem_post(&self->sem);

        // wait for it to stop
        // (could use counter, etc. to limit wait)
        int test=0;
        while (pthread_kill(self->thread,0) == 0) {
            MDEBUG(MD_XF_LOGGER,"waiting for thread to exit...\
"
,test);
            delay_msec(50);
        }

        // even though thread is finished, need to call join
        // otherwise, it will not release its memory (and valgrind indicates a leak)
        test=pthread_join(self->thread,NULL);
        return 0;          
    }
    return -1;
}

内存泄漏是由于以下事实导致的:如果线程不取消就保持运行状态,则不会释放相应的动态分配的内存。将pthread_cancel()连同pthread_cleanup_push(CleanupHandler,NULL)和pthread_cleanup_pop(0)一起使用,可以在取消后进行线程清理。