即使状态分离,pthread 中的内存泄漏

Memory leaks in pthread even if the state is detached

我正在学习 pthreads 编程。

我了解到线程有两种状态: 1.可加入 2. 可拆卸

在 Joinable 的情况下,我们需要调用 pthread_join 来释放资源(堆栈),而在 detached 的情况下则不需要调用 pthread_join 并且资源将在线程退出。

我写了一个示例程序来观察行为

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

void *threadFn(void *arg)
{

 pthread_detach(pthread_self());
 sleep(1);
 printf("Thread Fn\n");
 pthread_exit(NULL);
}

int main(int argc, char *argv[])
{

 pthread_t tid;
 int ret = pthread_create(&tid, NULL, threadFn, NULL);

 if (ret != 0) {
  perror("Thread Creation Error\n");
  exit(1);
 }
 printf("After thread created in Main\n");
 pthread_exit(NULL);
}

当我尝试使用 valgrind 检查任何内存泄漏时,它给了我 272 字节的泄漏。你能告诉我为什么这里会发生泄漏吗?

$valgrind --leak-check=full ./app
==38649== 
==38649== HEAP SUMMARY:
==38649==     in use at exit: 272 bytes in 1 blocks
==38649==   total heap usage: 7 allocs, 6 frees, 2,990 bytes allocated
==38649== 
==38649== 272 bytes in 1 blocks are possibly lost in loss record 1 of 1
==38649==    at 0x4C31B25: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==38649==    by 0x40134A6: allocate_dtv (dl-tls.c:286)
==38649==    by 0x40134A6: _dl_allocate_tls (dl-tls.c:530)
==38649==    by 0x4E44227: allocate_stack (allocatestack.c:627)
==38649==    by 0x4E44227: pthread_create@@GLIBC_2.2.5 (pthread_create.c:644)
==38649==    by 0x108902: main (2.c:18)
==38649== 
==38649== LEAK SUMMARY:
==38649==    definitely lost: 0 bytes in 0 blocks
==38649==    indirectly lost: 0 bytes in 0 blocks
==38649==      possibly lost: 272 bytes in 1 blocks
==38649==    still reachable: 0 bytes in 0 blocks
==38649==         suppressed: 0 bytes in 0 blocks
==38649== 
==38649== For counts of detected and suppressed errors, rerun with: -v
==38649== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

您的期望是正确的,一旦您调用 pthread_exit.

,主线程中不应有任何泄漏

但是,您观察到的是您正在使用的实现(很可能是 glibc)的一个怪癖 - pthreads 库(glibc 实现)re-uses 最初为线程分配的堆栈 - 就像缓存以便以前分配的堆栈可以 re-used 尽可能。

Valgrind 仅报告它 "sees" 的内容(已分配但未分配 de-allocated)。但这不是真正的泄漏,因此您无需担心。

如果您 "reverse" 逻辑(主线程作为最后一个线程退出)那么您将不会看到泄漏,因为最初分配的堆栈 space 已被主线程正确释放。但是这个泄漏在任何情况下都不是真正的泄漏,您可以安全地忽略它。

你也可以设置一个suppression file,这样Valgrind就不会抱怨这个(就是通知Valgrind"I know this isn't not real leak, so don't report this"),比如:

{
   Pthread_Stack_Leaks_Ignore
   Memcheck:Leak
   fun:calloc
   fun:allocate_dtv
   fun:_dl_allocate_tls
   fun:allocate_stack
   fun:pthread_create*

}