Valgrind 说内存是 "definitely lost" 是什么意思?

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

以下程序:

#include <stdlib.h>

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

    return 0;
}

这样编译:

gcc -g -o prog prog.c

并使用 Valgrind 执行:

valgrind --leak-check=full ./prog

产生以下(截断的)输出:

...
==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
...

为什么 Valgrind 说未释放的内存“肯定丢失”了?

来自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.

但是,很明显我可以在程序退出之前轻松释放该块。我在这里错过了什么?内存不应该“仍然可以访问”吗?

Valgrind 正在检查内存泄漏,而您正在泄漏内存,因为您在退出前没有释放指针。你应该免费(my_str) .

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

Definitely Lost 意味着没有人再引用该内存位置,因此没有人可以释放该内存。在 运行 程序的上下文中,这将是一段没有人可以重用的内存(因此它丢失了)。当然在程序结束时没有人会再次使用它,但是一些内存可能会被另一个泄漏对象引用(并且会间接丢失),因此您可以根据这些提示调试您的程序。 link 下面显示了对该主题的讨论。

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

因为 - 一旦 main returns 变量 my_str 不再存在。因此,没有办法释放分配的内存。并且没有办法到达内存。没有人知道记忆在哪里。丢了。

注意:所有现代 OS 系统都会负责内存清理,因此这不是真正的问题。

这是“绝对迷路”与“仍然可以到达”的示例:

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

void *p;

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

这段代码中发生的事情如下:

  • 分配了10个字节,指向此内存的指针分配给全局p
  • 分配了 100 个字节,并将指向此内存的指针分配给全局 p。这会覆盖指向 10 个已分配字节的指针值,并且没有其他引用指向它。以至于记忆“肯定丢失”了。
  • 分配了50个字节并将指向此内存的指针分配给本地m
  • main returns 导致 m 的生命周期结束。结果,没有存储指向 50 字节内存指针的引用,因此内存“肯定丢失”了。
  • 指向 100 字节的指针值仍然存在于全局 p 中,因此由 atexit 或其他编译器特定方法调用的清理例程仍然可以清理该内存。所以它“仍然可以到达”。

当运行 valgrind 在此代码上时,它输出以下内容:

==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)

与上面的描述一致

总而言之,如果指向内存的指针存储在文件范围变量中或由任何“仍可访问”的内存指向,则该内存“仍然可访问”。否则丢失。