Valgrind Memory Leak Errors When Using Pthread_Create

pthread_create() and memory leaks

Prior to your edit of adding pthread_exit(0) to the end of main(), your program would finish executing before all the threads had finished running. valgrind thus reported the resources that were still being held by the threads that were still active at the time the program terminated, making it look like your program had a memory leak.

The call to pthread_exit(0) in main() makes the main thread wait for all the other spawned threads to exit before it itself exits. This lets valgrind observe a clean run in terms of memory utilization.

(I am assuming linux is your operating system below, but it seems you are running some variety of UNIX from your comments.)

The extra virtual memory you see is just linux assigning some pages to your program since it was a big memory user. As long as your resident memory utilization is low and constant when you reach the idle state, and the virtual utilization is relatively constant, you can assume your system is well behaved.

By default, each thread gets 2MB of stack space on linux. If each thread stack does not need that much space, you can adjust it by initializing a pthread_attr_t and setting it with a smaller stack size using pthread_attr_setstacksize(). What stack size is appropriate depends on how deep your function call stack grows and how much space the local variables for those functions take.

#define SMALLEST_STACKSZ PTHREAD_STACK_MIN
#define SMALL_STACK (24*1024)
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, SMALL_STACK);
/* ... */
pthread_create(&my_thread, &attr, run_thread, (void *)thread_count);
/* ... */
pthread_attr_destroy(&attr);

c pthreads + valgrind = memory leak : why?

You have a bug in when your threads are detached, causing undefined behavior.

In main you have this line of code:

struct args_for_job_t args[MAX_THREADS];

Which you hand of pointers to your worker threads.

Then main() reaches this part

pthread_exit(NULL);

And main() ceases to exist, but you still may have worker threads around, that accesses the above args array that's on the stack of main() - which doesn't exist anymore.
Your worker threads might all finish before main() ends in some runs, but not in other runs.

why pthread causes a memory leak

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.

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.

Memory leaks in pthread even if the state is detached

Your expectation is correct that there shouldn't be any leaks in main thread once you call pthread_exit.

However, what you observe is a quirk of the implementation you're using (which is likely to be glibc) - pthreads library (glibc implementation) re-uses the initially allocated stack for threads - like a cache so that previously allocated stacks can be re-used whenever possible.

Valgrind simply reports what it "sees" (something was allocated but not de-allocated). But it's not a real leak, so you don't need to worry about this.

If you "reverse" the logic (main thread exits as the last thread) then you wouldn't see leaks because the initially allocated stack space is properly free'd by the main thread. But this leak isn't a real leak in any case and you can safely ignore this.

You can also setup a suppression file so that Valgrind doesn't complain about this (which is to inform Valgrind that "I know this isn't not real leak, so don't report this"), such as:

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

}

using pthread with memory leak

Your leak is because the memory you allocate has no corresponding free action.

The code you're using appears to be trying to convey a dynamic allocation back to the caller. Proper use of pthread_join and its second parameter can recoup that memory pointer, which can then be properly freed.

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>

void* runMe(void *pv)
{
int *arg = pv;
printf("Hello %d from %x\n", *arg, (unsigned int)pthread_self());
int *ret = malloc( sizeof *ret );
*ret = *arg + 4; // note this value '4' will be different in the quiz!
return ret;
}

int run_threads(int n) {
pthread_t thr[n];
int thr_args[n];
int total = 0;

for (int i=0; i<n; i++) {
thr_args[i] = i;
pthread_create(thr+i, NULL, runMe, thr_args+i);

}
for (int j=0; j<n; j++)
{
// reap pointer from resulting thread.
void *res = NULL;
pthread_join(thr[j], &res);

int *ires = res;
printf("ires = %p; *ires = %d\n", ires, *ires);
free(ires);

total += thr_args[j];
}
return total;
}

int main()
{
run_threads(10);
}

Output (varies)

Hello 9 from b0a71000
Hello 0 from b05df000
Hello 7 from b096d000
Hello 2 from b06e3000
Hello 1 from b0661000
Hello 4 from b07e7000
Hello 3 from b0765000
Hello 5 from b0869000
Hello 6 from b08eb000
Hello 8 from b09ef000
ires = 0x600000; *ires = 4
ires = 0x2009e0; *ires = 5
ires = 0x600010; *ires = 6
ires = 0x500010; *ires = 7
ires = 0x2009f0; *ires = 8
ires = 0x2012c0; *ires = 9
ires = 0x600020; *ires = 10
ires = 0x400040; *ires = 11
ires = 0x400050; *ires = 12
ires = 0x500000; *ires = 13

I also took liberty to fix your incorrect, non-compliant function signature you were using. pthread_create requires the form:

void *proc(void *)

for the thread procedure. Anything not of that form isn't compliant, and should be avoided.



Related Topics



Leave a reply



Submit