代码很简单:
#include <vector>
int main() {
std::vector<int> v;
}
然后我用Valgrind构建并运行它:
g++ test.cc && valgrind ./a.out
==8511== Memcheck, a memory error detector
==8511== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==8511== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==8511== Command: ./a.out
==8511==
==8511==
==8511== HEAP SUMMARY:
==8511== in use at exit: 72,704 bytes in 1 blocks
==8511== total heap usage: 1 allocs, 0 frees, 72,704 bytes allocated
==8511==
==8511== LEAK SUMMARY:
==8511== definitely lost: 0 bytes in 0 blocks
==8511== indirectly lost: 0 bytes in 0 blocks
==8511== possibly lost: 0 bytes in 0 blocks
==8511== still reachable: 72,704 bytes in 1 blocks
==8511== suppressed: 0 bytes in 0 blocks
==8511== Rerun with --leak-check=full to see details of leaked memory
==8511==
==8511== For counts of detected and suppressed errors, rerun with: -v
==8511== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
问题是双重的:
(1)“总堆使用率”表示有1个alloc和0个free。我假设1 alloc是因为std :: vector实例需要堆中的内存块。没关系;但是为什么它不会在破坏期间释放内存?
(2)并且,如果它没有释放它,为什么“泄漏概要”中没有内存泄漏?
(3)顺便说一句,每行之前==8511==
是什么意思? (不过,我可以在手册中查一查。你不必回答这个问题)
谢谢!
报告的内存仍由C ++运行时使用。你不必担心它。 Valgrind的FAQ有关于这个问题的an entry:
首先:放松,这可能不是一个错误,而是一个功能。许多C ++标准库的实现都使用自己的内存池分配器。很多被破坏对象的内存不会立即被释放并返回给操作系统,而是保存在池中以供以后重复使用。
(1)正确实现的默认构造的std::vector
不分配。 Esp不是72k。尝试使用--leak-check=full --track-origins=yes
运行,也许它显示了分配的起源
(2)它说,见:仍然可以到达。内存尚未泄露,因为仍然有一个指向它的句柄(例如:一个指针)。
(3)它是应用程序的进程ID。
您看到的72kb是由C ++运行时为其“紧急异常处理池”分配的。即使bad_alloc
无法再分配任何内容,此池也可用于分配异常对象(例如malloc
异常)。我们在启动时预先分配,所以如果malloc
内存不足,我们仍然会抛出bad_alloc
异常。
具体数字来自此代码:
// Allocate the arena - we could add a GLIBCXX_EH_ARENA_SIZE environment
// to make this tunable.
arena_size = (EMERGENCY_OBJ_SIZE * EMERGENCY_OBJ_COUNT
+ EMERGENCY_OBJ_COUNT * sizeof (__cxa_dependent_exception));
arena = (char *)malloc (arena_size);
较新版本的valgrind
知道这个紧急EH池,并在进程退出之前调用一个特殊函数来释放它,这样你就看不到in use at exit: 72,704 bytes in 1 blocks
了。之所以这样做是因为有太多人不理解仍然在使用(并且仍然可以访问)的内存不是泄漏,并且人们一直抱怨它。所以现在valgrind释放它,只是为了阻止人们抱怨。当没有在valgrind下运行时,池不会被释放,因为这样做是不必要的(操作系统将在进程退出时回收它)。