简体   繁体   English

为什么pthread导致内存泄漏

[英]why pthread causes a memory leak

Whenever I create a pthread, valgrind outputs a memory leak, 每当我创建一个pthread时,valgrind就会输出内存泄漏,

For example the below code: 例如下面的代码:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h> 

void *timer1_function (void *eit){
  (void) eit;
    printf("hello world\n");
    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 outputs valgrind输出

==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

why pthread_create cause a problem although I was using the man page as reference, and how can I fix it? 虽然我使用手册页作为参考,为什么pthread_create会导致问题,我该如何解决?

A thread is an allocated resource and you did not free it before exiting. 线程是已分配的资源,您在退出之前没有释放它。 You should call pthread_join ; 你应该调用pthread_join ; this would also eliminate the need for your hackish and incorrect sleep loop. 这也可以消除你的hackish和不正确的睡眠循环的需要。

It's possible that even once you fix this, valgrind will still see a "leak", since some implementations of POSIX threads (I'm guessing you're using glibc/NPTL) cache and reuse thread resources rather than freeing them fully. 有可能即使你解决了这个问题,valgrind仍会看到“泄漏”,因为POSIX线程的一些实现(我猜你正在使用glibc / NPTL)缓存并重用线程资源而不是完全释放它们。 I'm not sure if valgrind works around this or not. 我不确定valgrind是否可以解决这个问题。

I think that valgrind analyzes the state of your program at the time it exits, which is likely before the thread finishes its execution: two microseconds may not be enough to write "Hello, world!\\n" to console. 我认为valgrind在程序退出时分析程序的状态,这可能在线程完成执行之前:2微秒可能不足以将"Hello, world!\\n"写入控制台。 Adding a call to pthread_join should fix this leak: 添加对pthread_join的调用应修复此泄漏:

pthread_join(timer1, NULL);

I've seen similar results when I fail to call pthread_join. 当我没有调用pthread_join时,我看到了类似的结果。

When I do call pthread_join, Valgrind will indicate no memory errors or leaks. 当我调用pthread_join时,Valgrind将指示没有内存错误或泄漏。 I've had a clean result using pthread_kill to see if the thread still exists, then calling join to clean up and release resources. 我使用pthread_kill查看线程是否仍然存在,然后调用join来清理和释放资源。

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...\n",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;
}

The leak that shows up is related to the DTV (Dynamic Thread Vector) structure that is allocated in the child thread's local storage (tls). 显示的泄漏与在子线程的本地存储(tls)中分配的DTV(动态线程向量)结构有关。

Using pthread_join() in the main thread (ie the thread that spawned the child) will ensure to fix the leak. 在主线程中使用pthread_join() (即生成子进程的线程)将确保修复泄漏。 For use cases where pthread_join() call is not required, calling pthread_detach with child pthread_t ensures the memory is released. 对于那些使用案例pthread_join()不需要调用,调用pthread_detach与孩子的pthread_t确保内存被释放。

From man for pthread_detach : 来自man for pthread_detach

The pthread_detach() function marks the thread identified by thread as detached. pthread_detach()函数将线程标识的线程标记为已分离。 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. 当分离的线程终止时,其资源会自动释放回系统,而不需要另一个线程与终止的线程连接。

memory leak is a result of the fact that if the thread is left running without cancellation , then the corresponding dynamically allocated memory is not freed. 内存泄漏是由于如果线程在没有取消的情况下保持运行的事实,则不会释放相应的动态分配的内存。 Use pthread_cancel() along with pthread_cleanup_push(CleanupHandler, NULL) and pthread_cleanup_pop(0) to do the thread cleanup after cancellation. 使用pthread_cancel()和pthread_cleanup_push(CleanupHandler,NULL)和pthread_cleanup_pop(0)在取消后进行线程清理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM