即使状态分离,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*
}
我正在学习 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*
}