C语言 为什么 pthread 会导致内存泄漏

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17642433/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 06:54:15  来源:igfitidea点击:

why pthread causes a memory leak

cmemory-leakspthreadsposixvalgrind

提问by Johan Elmander

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 会导致问题,我该如何解决?

回答by R.. GitHub STOP HELPING ICE

A thread is an allocated resource and you did not free it before exiting. You should call pthread_join; this would also eliminate the need for your hackish and incorrect sleep loop.

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

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. I'm not sure if valgrind works around this or not.

有可能即使你修复了这个问题,valgrind 仍然会看到“泄漏”,因为 POSIX 线程的一些实现(我猜你正在使用 glibc/NPTL)缓存和重用线程资源而不是完全释放它们。我不确定 valgrind 是否可以解决这个问题。

回答by dasblinkenlight

I think that valgrindanalyzes 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. Adding a call to pthread_joinshould fix this leak:

我认为这会valgrind分析程序退出时的状态,这可能是在线程完成执行之前:两微秒可能不足以写入"Hello, world!\n"控制台。添加调用pthread_join应修复此泄漏:

pthread_join(timer1, NULL);

回答by klheadley

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. 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_join 时,Valgrind 将指示没有内存错误或泄漏。我使用 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;
}

回答by daemon155

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 (i.e. the thread that spawned the child) will ensure to fix the leak. For use cases where pthread_join()call is not required, calling pthread_detachwith child pthread_t ensures the memory is released.

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

From man for 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_detach()函数将线程标识的线程标记为分离。当一个分离的线程终止时,它的资源会自动释放回系统,而无需另一个线程与终止的线程连接。

回答by wrapperm

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) 在取消后进行线程清理。