1

I made an array of threads but I do not use all of them. it turn out to be a memory leak. Is there any function that I could use to free the memory?

void func( args... )
{
.
.
.
pthread_t threads[10]

int i;
for( i = 0; i < 8; i++ )
{
    /* create 8 threads */
}
for( i = 0; i < 8; i++ )
{
    /* join 8 threads */
}
.
.
.
return;
}

The code I used for experiment is here. I make it use more thread than I want to. if I don't add the 10 more threads, there will be no leak at all. it takes some text files as argument compile and run with

gcc -g -Wall -pthread test.c valgrind --tool=memcheck --leak-check=full --show-reachable=yes ./a.out *.txt

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

#define DEBUG 0
#define BUFLEN 10000

/* function declaration */
static void* countLines(void* input);
static void error(const char*);

/* global variable */
static int total_th; /* total number of threads */
static int count_th; /* the count of the finished threads */

/*
 * main starts here
 */
int main(int argc, char** argv)
{
    /* if there is no command line arguments, print error */
    if(argc < 2)
    {
        error("there should be at lease one argument!\n");
        exit(-1);
    }

    /* initialize thread counters */
    total_th = argc - 1;
    count_th = 0;

    pthread_t pt[ total_th + 10]; /* the ptreads to read file lines */

    /* create threads for each file */
    int i;
    for(i = 0; i < total_th; i++)
    {
        if((pthread_create(&pt[i], NULL,
                countLines, (void*) argv[i + 1])) != 0)
        {
            fprintf(stderr, "error in thread create\n");
        }
    }

    /* main thread wait for all the slaves to finish */
    for(i = 0; i < total_th; i++)
    {
        if(pthread_join(pt[i], NULL) != 0)
            fprintf(stderr, "error in thread join\n");
    }

    return(0);
}

/**
 * void* countLines(void * input)
 * @param input: the name of the file
 * @return NULL
 * count the number of lines for the specified file
 */
void* countLines(void * input)
{
    char* fileName = (char*) input; /* file name */
    int newLineCount = 0; /* a count of the new line character */
    int fd; /*file descriptor*/

    /* open file, if open fail print error message */
    if((fd = open(fileName, O_RDONLY)) == -1)
    {
        fprintf(stderr, "Can not open file - %s\n", fileName);
        count_th++;
        return NULL;
    }

    char buf[BUFLEN]; /* the buffer to be read */
    int lastRead; /* the number of characters read to buffer */

    /* read the file */
    while((lastRead = read(fd, buf, BUFLEN)))
    {
        /* detect error state */
        if(lastRead == -1)
        {
            fprintf(stderr, "error reading file %s!\n", fileName);
            count_th++;
            return NULL;
        }

        /* count the new line character */
        int i;
        for(i = 0; i < lastRead; i++)
        {
            if(buf[i] == '\n')
            {
                newLineCount++;
            }
        }
    }

    printf("There are %d lines in %s\n", newLineCount, fileName);

    close(fd); /* close file descriptor */
    pthread_exit( NULL );
}

/**
 * void error(const char*str )
 * @param str error message
 * print an error message
 */
void error(const char *str)
{
    perror(str);
    exit(-1);
}

here is what valgrind prints when I run the program. The memory leak is from the function I create the unused threads. somethimes it prints this message, sometimes it does not.

 ==4737== 
==4737== HEAP SUMMARY:
==4737==     in use at exit: 1,590 bytes in 5 blocks
==4737==   total heap usage: 12 allocs, 7 frees, 3,494 bytes allocated
==4737== 
==4737== 36 bytes in 1 blocks are still reachable in loss record 1 of 5
==4737==    at 0x4C28F9F: malloc (vg_replace_malloc.c:236)
==4737==    by 0x40085BF: _dl_map_object (dl-load.c:162)
==4737==    by 0x4012B79: dl_open_worker (dl-open.c:226)
==4737==    by 0x400E9C5: _dl_catch_error (dl-error.c:178)
==4737==    by 0x40133A9: _dl_open (dl-open.c:569)
==4737==    by 0x516AF6F: do_dlopen (dl-libc.c:86)
==4737==    by 0x400E9C5: _dl_catch_error (dl-error.c:178)
==4737==    by 0x516B029: __libc_dlopen_mode (dl-libc.c:47)
==4737==    by 0x4E3F75B: pthread_cancel_init (unwind-forcedunwind.c:53)
==4737==    by 0x4E3F91B: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)
==4737==    by 0x4E3D9DF: __pthread_unwind (unwind.c:130)
==4737==    by 0x4E380A4: pthread_exit (pthreadP.h:265)
==4737== 
==4737== 36 bytes in 1 blocks are still reachable in loss record 2 of 5
==4737==    at 0x4C28F9F: malloc (vg_replace_malloc.c:236)
==4737==    by 0x400B43C: _dl_new_object (dl-object.c:164)
==4737==    by 0x4006575: _dl_map_object_from_fd (dl-load.c:967)
==4737==    by 0x400831E: _dl_map_object (dl-load.c:2260)
==4737==    by 0x4012B79: dl_open_worker (dl-open.c:226)
==4737==    by 0x400E9C5: _dl_catch_error (dl-error.c:178)
==4737==    by 0x40133A9: _dl_open (dl-open.c:569)
==4737==    by 0x516AF6F: do_dlopen (dl-libc.c:86)
==4737==    by 0x400E9C5: _dl_catch_error (dl-error.c:178)
==4737==    by 0x516B029: __libc_dlopen_mode (dl-libc.c:47)
==4737==    by 0x4E3F75B: pthread_cancel_init (unwind-forcedunwind.c:53)
==4737==    by 0x4E3F91B: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)
==4737== 
==4737== 56 bytes in 1 blocks are still reachable in loss record 3 of 5
==4737==    at 0x4C28F9F: malloc (vg_replace_malloc.c:236)
==4737==    by 0x400D187: _dl_map_object_deps (dl-deps.c:505)
==4737==    by 0x4012BD6: dl_open_worker (dl-open.c:263)
==4737==    by 0x400E9C5: _dl_catch_error (dl-error.c:178)
==4737==    by 0x40133A9: _dl_open (dl-open.c:569)
==4737==    by 0x516AF6F: do_dlopen (dl-libc.c:86)
==4737==    by 0x400E9C5: _dl_catch_error (dl-error.c:178)
==4737==    by 0x516B029: __libc_dlopen_mode (dl-libc.c:47)
==4737==    by 0x4E3F75B: pthread_cancel_init (unwind-forcedunwind.c:53)
==4737==    by 0x4E3F91B: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)
==4737==    by 0x4E3D9DF: __pthread_unwind (unwind.c:130)
==4737==    by 0x4E380A4: pthread_exit (pthreadP.h:265)
==4737== 
==4737== 288 bytes in 1 blocks are still reachable in loss record 4 of 5
==4737==    at 0x4C279F2: calloc (vg_replace_malloc.c:467)
==4737==    by 0x4010359: _dl_check_map_versions (dl-version.c:300)
==4737==    by 0x4012EF0: dl_open_worker (dl-open.c:269)
==4737==    by 0x400E9C5: _dl_catch_error (dl-error.c:178)
==4737==    by 0x40133A9: _dl_open (dl-open.c:569)
==4737==    by 0x516AF6F: do_dlopen (dl-libc.c:86)
==4737==    by 0x400E9C5: _dl_catch_error (dl-error.c:178)
==4737==    by 0x516B029: __libc_dlopen_mode (dl-libc.c:47)
==4737==    by 0x4E3F75B: pthread_cancel_init (unwind-forcedunwind.c:53)
==4737==    by 0x4E3F91B: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)
==4737==    by 0x4E3D9DF: __pthread_unwind (unwind.c:130)
==4737==    by 0x4E380A4: pthread_exit (pthreadP.h:265)
==4737== 
==4737== 1,174 bytes in 1 blocks are still reachable in loss record 5 of 5
==4737==    at 0x4C279F2: calloc (vg_replace_malloc.c:467)
==4737==    by 0x400B1CD: _dl_new_object (dl-object.c:77)
==4737==    by 0x4006575: _dl_map_object_from_fd (dl-load.c:967)
==4737==    by 0x400831E: _dl_map_object (dl-load.c:2260)
==4737==    by 0x4012B79: dl_open_worker (dl-open.c:226)
==4737==    by 0x400E9C5: _dl_catch_error (dl-error.c:178)
==4737==    by 0x40133A9: _dl_open (dl-open.c:569)
==4737==    by 0x516AF6F: do_dlopen (dl-libc.c:86)
==4737==    by 0x400E9C5: _dl_catch_error (dl-error.c:178)
==4737==    by 0x516B029: __libc_dlopen_mode (dl-libc.c:47)
==4737==    by 0x4E3F75B: pthread_cancel_init (unwind-forcedunwind.c:53)
==4737==    by 0x4E3F91B: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)
==4737== 
==4737== LEAK SUMMARY:
==4737==    definitely lost: 0 bytes in 0 blocks
==4737==    indirectly lost: 0 bytes in 0 blocks
==4737==      possibly lost: 0 bytes in 0 blocks
==4737==    still reachable: 1,590 bytes in 5 blocks
==4737==         suppressed: 0 bytes in 0 blocks
==4737== 
==4737== For counts of detected and suppressed errors, rerun with: -v
==4737== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
xinghua
  • 139
  • 2
  • 13
  • 1
    Do you know *what* exactly is leaking memory? What do you mean you don't use all of the threads? – Chris Mar 31 '12 at 00:24
  • What exactly are you storing in your array? (I have a feeling you're prematurely blaming _it_ rather than something else.) – sarnold Mar 31 '12 at 00:27
  • i know my program is leaking memory because valgrind prints the leak message. as the example code snippet shows, I did not create and join the 2 of the threads. it turn out to be a memory leak. – xinghua Mar 31 '12 at 00:27
  • some times it leaks, sometimes it is not leaking, I don't know why – xinghua Mar 31 '12 at 00:31
  • @xinghua, what is happening in the actual thread? (Is there a call to `malloc` without the corresponding call to `free`?) – huon Mar 31 '12 at 00:53
  • @dbaupp there is no malloc and free at all, this error is caused by the 2 unused threads. any suggestions?? – xinghua Mar 31 '12 at 00:55
  • @xinghua, how do you *know* that it is called by the unused threads? (If you change the `10` to an `8` does valgrind still print the message sometimes?) – huon Mar 31 '12 at 00:57
  • I make an experiment on this. let me show you the code in a min – xinghua Mar 31 '12 at 01:00
  • @dbaupp I use other programs to test it and the result is the same, sometimes it frees all memory, sometimes not. – xinghua Mar 31 '12 at 01:10

1 Answers1

3

The "problem" the use of pthread_exit. This question gives some details, specifically:

Several glibc functions allocate memory with malloc() the first time they're called, which they keep allocated for the remainder of the process lifetime. glibc doesn't bother to free this memory at process exit, since it knows that the process is being torn down anyway - it'd just be a waste of CPU cycles.

So this memory leak is fine.

However, to actually get rid of the valgrind messages, you can use return NULL; in place of pthread_exit(NULL); on the last line of countLines, since you are just returning from the start routine.

Community
  • 1
  • 1
huon
  • 94,605
  • 21
  • 231
  • 225