2

Please take as an example below. It seems there is no memory leak but why total heap usage and bytes allocated keeps increasing? If I remove first part(test1), valgrind result does not show any increasing heap and always total heap usage: 1 allocs, 1 frees, 568 bytes allocated

code example:

int main(void)
{
    while(1)
    {
        FILE *test1;
        test1 = fopen("test1", "w");
        fprintf(test1, "something\n");
        fclose(test1);

        pid_t childPid; 
        childPid = fork();
        if(childPid == 0)
        {
            int j;
            FILE *test2;
            test2 = fopen("test2", "w");

            for(j = 0; j < 4; j++)
            {
                fprintf(test2, "something\n");
            }
            fclose(test2);

            exit(0);
        }
        else 
        {    
             int returnStatus;    
             waitpid(childPid, &returnStatus, 0);
        }   

        sleep(2);
    }
    return 0;
}

valgrind result:

==6314== Memcheck, a memory error detector
==6314== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==6314== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==6314== Command: ./test
==6314== Parent PID: 6313
==6314== 
==6315== 
==6315== HEAP SUMMARY:
==6315==     in use at exit: 0 bytes in 0 blocks
==6315==   total heap usage: 2 allocs, 2 frees, 1,136 bytes allocated
==6315== 
==6315== All heap blocks were freed -- no leaks are possible
==6315== 
==6315== For counts of detected and suppressed errors, rerun with: -v
==6315== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==6317== 
==6317== HEAP SUMMARY:
==6317==     in use at exit: 0 bytes in 0 blocks
==6317==   total heap usage: 3 allocs, 3 frees, 1,704 bytes allocated
==6317== 
==6317== All heap blocks were freed -- no leaks are possible
==6317== 
==6317== For counts of detected and suppressed errors, rerun with: -v
==6317== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==6319== 
==6319== HEAP SUMMARY:
==6319==     in use at exit: 0 bytes in 0 blocks
==6319==   total heap usage: 4 allocs, 4 frees, 2,272 bytes allocated
==6319== 
==6319== All heap blocks were freed -- no leaks are possible
==6319== 
==6319== For counts of detected and suppressed errors, rerun with: -v
==6319== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Dmitry
  • 6,716
  • 14
  • 37
  • 39
Dinn
  • 21
  • 2
  • 2
    Not sure where the confusion is - you're opening a file on each iteration of the while loop and that is going to need memory allocated. – Chris Turner Oct 02 '17 at 09:41
  • @ChrisTurner I think it's as simple as that, OP does not know that file opening implies memory allocated by the lib functions. Looking for more specific info ATM – Hans Petter Taugbøl Kragset Oct 02 '17 at 09:43
  • How do you terminate the application? I see no terminating condition; it keeps looping and forking. – Paul Ogilvie Oct 02 '17 at 10:06
  • Chris Turner 49, I do understand opening file need memory allocated. But as I stated above if I comment out part(test1) and let only child do a task which do opening file on each iteration, valgrind report does not show any increase memory allocated. – Dinn Oct 02 '17 at 10:33
  • vargarid result: without parrent opening any files. ==6443== HEAP SUMMARY: ==6443== in use at exit: 0 bytes in 0 blocks ==6443== total heap usage: 1 allocs, 1 frees, 568 bytes allocated ==6443== ==6443== All heap blocks were freed -- no leaks are possible ==6443== ==6443== For counts of detected and suppressed errors, rerun with: -v ==6443== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) ==6446== ==6446== HEAP SUMMARY: ==6446== in use at exit: 0 bytes in 0 blocks ==6446== total heap usage: 1 allocs, 1 frees, 568 bytes allocated – Dinn Oct 02 '17 at 10:57
  • @Dinn I addressed this in my answer below now. – Hans Petter Taugbøl Kragset Oct 02 '17 at 11:15
  • @Hans Petter thanks for the explanation. So this kind of code is totally useless! What is an option to achieve same goal? I have to add here before "waitpid" code, parrent do some task while child do some other task. – Dinn Oct 03 '17 at 03:40
  • Then you just add the task there. The increasing memory allocation from valgrind is not an issue, it is not actually increasing (as in a memory leak), it is just re-allocating bytes again and again, bringing the total up, but your program still consumes the same amount of actual memory every iteration (as long as you close files). Maybe I don't understand your problem? – Hans Petter Taugbøl Kragset Oct 03 '17 at 09:03
  • Do you mean that the increasing memory allocation only happened in valgrind? So if i run standalone program without valgrind, the increasing memory allocation will never happen? Sorry my english not good. – Dinn Oct 03 '17 at 13:11

1 Answers1

1

Using massif as described here, we get output about heap usage for our program. I used it like this

valgrind --tool=massif ./a.out

Then, in the output file from massif (one for each child process also), we can see lines like this:

[...]
#-----------
snapshot=3
#-----------
time=115870
mem_heap_B=4648
mem_heap_extra_B=24
mem_stacks_B=0
heap_tree=peak
n2: 4648 (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
 n1: 4096 0x4E9F380: _IO_file_doallocate (filedoalloc.c:101)
  n1: 4096 0x4EAE874: _IO_doallocbuf (genops.c:398)
   n1: 4096 0x4EADA46: _IO_file_overflow@@GLIBC_2.2.5 (fileops.c:828)
    n1: 4096 0x4EAC11B: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1339)
     n1: 4096 0x4EA0A79: fwrite (iofwrite.c:39)
      n0: 4096 0x1088E5: main (in /home/.../a.out)
 n1: 552 0x4E9FF2B: __fopen_internal (iofopen.c:69)
  n0: 552 0x1088C4: main (in /home/.../a.out)
[...]

Here we see that various library functions related to file operations (fileops.c) allocate memory for your FILEs (fwrite shown here).

Why does the allocation not increase when you comment out the test1-part?

Well, if you comment out that part, you remove the part of code that is run in each run of the loop. The code that is left is only run in a child process, meaning the total memory allocation (and allocation count) stays constant at 0 for the parent process. All children will do the same operations, resulting in the same amount of allocations.


Generally, the C code used in the standard library sometimes require memory to do what they need to do. File functionality needs buffer space to store bytes to read/write, as files are read as disk blocks on the lower level, and more.

Also, from the man page of fclose:

The fclose() function flushes the stream pointed to by stream (writing any buffered output data using fflush(3)) and closes the underlying file descriptor.

Here some buffered data is referred to, and these buffers are also freed when you call fclose.