简体   繁体   中英

What does Valgrind mean when it says memory is “definitely lost”?

The following program:

#include <stdlib.h>

int main(void)
{
    char *my_str = malloc(42 * sizeof(char));

    return 0;
}

Compiled as such:

gcc -g -o prog prog.c

And executed with Valgrind as such:

valgrind --leak-check=full ./prog

Produces the following (truncated) output:

...
==18424== HEAP SUMMARY:
==18424==     in use at exit: 42 bytes in 1 blocks
==18424==   total heap usage: 1 allocs, 0 frees, 42 bytes allocated
==18424== 
==18424== 42 bytes in 1 blocks are definitely lost in loss record 1 of 1
==18424==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18424==    by 0x10865B: main (main.c:5)
==18424== 
==18424== LEAK SUMMARY:
==18424==    definitely lost: 42 bytes in 1 blocks
==18424==    indirectly lost: 0 bytes in 0 blocks
==18424==      possibly lost: 0 bytes in 0 blocks
==18424==    still reachable: 0 bytes in 0 blocks
==18424==         suppressed: 0 bytes in 0 blocks
...

Why does Valgrind say that the unfreed memory is "definitely lost"?

From the Valgrind Memcheck docs :

This means that no pointer to the block can be found. The block is classified as "lost", because the programmer could not possibly have freed it at program exit, since no pointer to it exists. This is likely a symptom of having lost the pointer at some earlier point in the program.

However, it's pretty clear that I could have easily freed the block before program exit. What am I missing here? Shouldn't the memory be "still reachable"?

Here's an example of "definitely lost" vs. "still reachable":

#include <stdio.h>
#include <stdlib.h>

void *p;

int main()
{
    p = malloc(10);
    p = malloc(100);
    void *m = malloc(50);
    return 0;
}

What happens in this code is the following:

  • 10 bytes are allocated and the pointer to this memory is assigned to the global p .
  • 100 bytes are allocated and the pointer to this memory is assigned to the global p . This overwrites the pointer value that pointed to 10 allocated bytes, and there is no other reference to it. So that memory is "definitely lost".
  • 50 bytes are allocated and the pointer to this memory is assigned to the local m .
  • main returns causing the lifetime of m to end. As a result there is no reference stored to the memory pointer to 50 bytes so that memory is "definitely lost".
  • The pointer value pointing to 100 bytes still lives in the global p , so cleanup routines such as those called by atexit or other compiler specific methods could still clean up that memory. So it is "still reachable".

When running valgrind on this code, it outputs the following:

==60822== Memcheck, a memory error detector
==60822== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==60822== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==60822== Command: ./x1
==60822== 
==60822== 
==60822== HEAP SUMMARY:
==60822==     in use at exit: 160 bytes in 3 blocks
==60822==   total heap usage: 3 allocs, 0 frees, 160 bytes allocated
==60822== 
==60822== LEAK SUMMARY:
==60822==    definitely lost: 60 bytes in 2 blocks
==60822==    indirectly lost: 0 bytes in 0 blocks
==60822==      possibly lost: 0 bytes in 0 blocks
==60822==    still reachable: 100 bytes in 1 blocks
==60822==         suppressed: 0 bytes in 0 blocks
==60822== Rerun with --leak-check=full to see details of leaked memory
==60822== 
==60822== For counts of detected and suppressed errors, rerun with: -v
==60822== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Which is consistent with the description above.

So to summarize, memory is "still reachable" if a pointer to it is stored either in a file scope variable or is pointed to by any "still reachable" memory. Otherwise it is lost.

Why does Valgrind say that the unfreed memory is "definitely lost"?

Because - once main returns the variable my_str doesn't exist anymore. Consequently, there is no way to free the allocated memory. And there is no way to reach the memory. No one know where the memory is. It's lost.

Note: All modern OS systems will however take care of the memory clean up so it's not a real problem.

Valgrind is checking for memory leaks, and you are leaking memory as you didn't free the pointer before exit. You should free(my_str).

int main(void)
{
    char *my_str = malloc(42 * sizeof(char));
    free (my_str);
    return 0;
}

Definitely Lost mean that nobody has a reference to that memory location anymore, so nobody could free that memory. In a context of a running program that will be a segment of memory that nobody could reuse (so it is lost). Of course at the end of the program nobody will ever use it again, but some of the memory could be referenced by another leaking object (and will be an indirect lost), so with those hints you can debug your program. The link bellow shows a discussion on the topic.

This is a complete response on why you should free memory before exit

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM