Почему pthread вызывает утечку памяти
Всякий раз, когда я создаю pthread, valgrind выводит утечку памяти,
Например код ниже:
#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 выходы
==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 вызывает проблему, хотя я использовал справочную страницу в качестве ссылки, и как я могу это исправить?
5 ответов
Поток является выделенным ресурсом, и вы не освободили его перед выходом. Вам следует позвонить pthread_join
; это также устранит необходимость в вашем хакерском и неправильном цикле сна.
Возможно, что даже после того, как вы это исправите, valgrind все равно увидит "утечку", поскольку некоторые реализации потоков POSIX (я предполагаю, что вы используете glibc/NPTL) кэшируют и повторно используют ресурсы потоков, а не освобождают их полностью. Я не уверен, работает ли Valgrind вокруг этого или нет.
Я думаю что valgrind
анализирует состояние вашей программы на момент ее выхода, что, вероятно, до того, как поток завершит свое выполнение: двух микросекунд может быть недостаточно для записи "Hello, world!\n"
утешить. Добавление звонка pthread_join
следует исправить эту утечку:
pthread_join(timer1, NULL);
Я видел похожие результаты, когда мне не удается вызвать pthread_join.
Когда я вызываю pthread_join, Valgrind не сообщит об ошибках памяти или утечках. У меня был чистый результат с использованием pthread_kill, чтобы увидеть, существует ли еще поток, а затем вызов объединения для очистки и освобождения ресурсов.
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;
}
Обнаруженная утечка связана со структурой DTV (динамический вектор потока), которая размещена в локальном хранилище дочернего потока (tls).
С помощью pthread_join()
в основной нити (т. е. нить, которая породила ребенка) обеспечит исправление утечки. Для случаев использования, где pthread_join()
звонок не требуется, звоню pthread_detach
с дочерним pthread_t обеспечивает освобождение памяти.
От человека для pthread_detach
:
pthread_detach()
функция отмечает нить, идентифицированную нитью, как отсоединенную. Когда отключенный поток завершается, его ресурсы автоматически возвращаются обратно в систему без необходимости присоединения другого потока к завершенному потоку.
Утечка памяти является результатом того факта, что если поток остается запущенным без отмены, то соответствующая динамически распределенная память не освобождается. Используйте pthread_cancel() вместе с pthread_cleanup_push(CleanupHandler, NULL) и pthread_cleanup_pop(0) для очистки потока после отмены.